diff options
author | David Golden <xdg@xdg.me> | 2019-06-26 15:52:26 -0400 |
---|---|---|
committer | David Golden <xdg@xdg.me> | 2019-06-26 16:59:48 -0400 |
commit | 6cb22a4feef4e5eb03412e392d2274707965f9b9 (patch) | |
tree | 61219f9a7117fba82ae5715addbfebb062211e48 | |
parent | 42c1fa4f55a55fd9cc98a57f691160152acacf7e (diff) | |
download | mongo-6cb22a4feef4e5eb03412e392d2274707965f9b9.tar.gz |
Import tools: d7cc167b3f43f7264b6e4350a1632dd730793d6b from branch v4.1
ref: 25f23659be..d7cc167b3f
for: 4.3.1
TOOLS-1801 text index collation creation may require explicit 'simple' locale
14 files changed, 1091 insertions, 140 deletions
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/Gopkg.lock b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/Gopkg.lock index b8e973ece01..63bbe06b62a 100644 --- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/Gopkg.lock +++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/Gopkg.lock @@ -104,7 +104,7 @@ [[projects]] branch = "master" - digest = "1:d60f927aee2981fec0cc764cc118f202964b6023ada356e532b6c708e489ec26" + digest = "1:65929a60fecb8d113b86f4a83d447f28f97a72bf0eafc760a6a41c287f08e362" name = "github.com/mongodb/mongo-tools-common" packages = [ "archive", @@ -125,7 +125,7 @@ "util", ] pruneopts = "T" - revision = "4316ec1965c626bbe74458444880c40950565e64" + revision = "947545918a26ddef9a4fa2ab3043b0d85071cb81" [[projects]] digest = "1:f363c75e8cac5653bc5c0c2b90cbd8a522fdc48c13a5f8d85078750f82d1a009" diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/binaryurl.py b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/binaryurl.py index df18a8146f1..41cfad63455 100644 --- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/binaryurl.py +++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/binaryurl.py @@ -48,10 +48,9 @@ if opts.version == "latest" or isVersionGreaterOrEqual(opts.version,"4.1.0"): opts.target = 'windows_x86_64-2012plus' def isCorrectVersion(version): + # for approximate match, ignore '-rcX' part, but due to json file ordering + # x.y.z will always be before x.y.z-rcX, which is what we want parts = version["version"].split("-") - # always skip '-rcX' versions - if len(parts) > 1: - return False actual = parts[0].split(".") desired = opts.version.split(".") for i in range(len(desired)): diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/common.yml b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/common.yml index 51b7f5734b2..55957624a17 100644 --- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/common.yml +++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/common.yml @@ -13,37 +13,43 @@ mongo_tools_variables: mongo_tools_task_lists: mac_task_list: &macos_tasks - name: dist - - name: integration - - name: integration-auth + - name: integration-4.0 + - name: integration-4.0-auth + - name: integration-4.2 + - name: integration-4.2-auth - name: qa-tests-3.2 - name: qa-tests-3.4 - name: qa-tests-3.6 - name: qa-tests-4.0 + - name: qa-tests-4.2 - name: qa-tests-unstable - - name: qa-dump-restore-gzip + - name: qa-dump-restore-gzip-4.2 - name: qa-dump-restore-gzip-3.2 - - name: qa-dump-restore-archiving + - name: qa-dump-restore-archiving-4.2 - name: qa-dump-restore-archiving-3.2 - name: unit - name: replay-dist - - name: replay-sanity_check - - name: replay-go_test - - name: replay-auth_test - - name: replay-sharded_test - - name: replay-repl_test + - name: replay-sanity_check-4.2 + - name: replay-go_test-4.2 + - name: replay-auth_test-4.2 + - name: replay-sharded_test-4.2 + - name: replay-repl_test-4.2 # Disabled due to TOOLS-2107 - # - name: replay-replay_test + # - name: replay-replay_test-4.2 macos_ssl_task_list: &macos_ssl_tasks - name: dist - name: qa-tests-4.0 + - name: qa-tests-4.2 - name: qa-tests-unstable - - name: native-cert-ssl + - name: native-cert-ssl-4.2 - name: unit - name: replay-dist rhel_x86_64_task_list: &rhel_x86_64_tasks - name: dist - - name: integration - - name: integration-auth + - name: integration-4.0 + - name: integration-4.0-auth + - name: integration-4.2 + - name: integration-4.2-auth - name: legacy30 - name: lint-go - name: format-go @@ -52,50 +58,59 @@ mongo_tools_variables: - name: qa-tests-3.4 - name: qa-tests-3.6 - name: qa-tests-4.0 + - name: qa-tests-4.2 - name: qa-tests-unstable - - name: qa-dump-restore-gzip + - name: qa-dump-restore-gzip-4.2 - name: qa-dump-restore-gzip-3.2 - - name: qa-dump-restore-archiving + - name: qa-dump-restore-archiving-4.2 - name: qa-dump-restore-archiving-3.2 - name: unit - name: vet - name: replay-dist - - name: replay-sanity_check - - name: replay-go_test - - name: replay-auth_test - - name: replay-sharded_test - - name: replay-repl_test + - name: replay-sanity_check-4.2 + - name: replay-go_test-4.2 + - name: replay-auth_test-4.2 + - name: replay-sharded_test-4.2 + - name: replay-repl_test-4.2 # Disabled due to TOOLS-2116 - # - name: replay-replay_test + # - name: replay-replay_test-4.2 rhel_x86_64_ssl_task_list: &rhel_x86_64_ssl_tasks - name: dist - - name: integration - - name: integration-auth + - name: integration-4.0 + - name: integration-4.0-auth + - name: integration-4.2 + - name: integration-4.2-auth - name: qa-tests-4.0 + - name: qa-tests-4.2 - name: qa-tests-unstable - - name: native-cert-ssl + - name: native-cert-ssl-4.2 - name: replay-dist rhel_x86_64_enterprise_task_list: &rhel_x86_64_enterprise_tasks - name: dist - - name: integration - - name: integration-auth + - name: integration-4.0 + - name: integration-4.0-auth + - name: integration-4.2 + - name: integration-4.2-auth # Disabled due to TOOLS-2119 # - name: kerberos - name: qa-tests-4.0 + - name: qa-tests-4.2 - name: qa-tests-unstable - - name: native-cert-ssl + - name: native-cert-ssl-4.2 - name: replay-dist - - name: replay-sanity_check - - name: replay-go_test - - name: replay-auth_test - - name: replay-sharded_test - - name: replay-repl_test + - name: replay-sanity_check-4.2 + - name: replay-go_test-4.2 + - name: replay-auth_test-4.2 + - name: replay-sharded_test-4.2 + - name: replay-repl_test-4.2 # Disabled due to TOOLS-2116 - # - name: replay-replay_test + # - name: replay-replay_test-4.2 ubuntu_x86_64_task_list: &ubuntu_x86_64_tasks - name: dist - - name: integration - - name: integration-auth + - name: integration-4.0 + - name: integration-4.0-auth + - name: integration-4.2 + - name: integration-4.2-auth - name: lint-go - name: format-go - name: lint-js @@ -103,63 +118,75 @@ mongo_tools_variables: - name: qa-tests-3.4 - name: qa-tests-3.6 - name: qa-tests-4.0 + - name: qa-tests-4.2 - name: qa-tests-unstable - - name: qa-dump-restore-gzip + - name: qa-dump-restore-gzip-4.2 - name: qa-dump-restore-gzip-3.2 - - name: qa-dump-restore-archiving + - name: qa-dump-restore-archiving-4.2 - name: qa-dump-restore-archiving-3.2 - name: unit - name: vet - name: replay-dist - - name: replay-sanity_check - - name: replay-go_test - - name: replay-auth_test - - name: replay-sharded_test - - name: replay-repl_test + - name: replay-sanity_check-4.2 + - name: replay-go_test-4.2 + - name: replay-auth_test-4.2 + - name: replay-sharded_test-4.2 + - name: replay-repl_test-4.2 # Disabled due to TOOLS-2108 - # - name: replay-replay_test + # - name: replay-replay_test-4.2 ubuntu_x86_64_ssl_task_list: &ubuntu_x86_64_ssl_tasks - name: dist - - name: integration - - name: integration-auth + - name: integration-4.0 + - name: integration-4.0-auth + - name: integration-4.2 + - name: integration-4.2-auth - name: qa-tests-4.0 + - name: qa-tests-4.2 - name: qa-tests-unstable - - name: native-cert-ssl + - name: native-cert-ssl-4.2 - name: replay-dist ubuntu_x86_64_enterprise_task_list: &ubuntu_x86_64_enterprise_tasks - name: dist - - name: integration - - name: integration-auth + - name: integration-4.0 + - name: integration-4.0-auth + - name: integration-4.2 + - name: integration-4.2-auth - name: kerberos - name: qa-tests-4.0 + - name: qa-tests-4.2 - name: qa-tests-unstable - - name: native-cert-ssl + - name: native-cert-ssl-4.2 - name: replay-dist - - name: replay-sanity_check - - name: replay-go_test - - name: replay-auth_test - - name: replay-sharded_test - - name: replay-repl_test + - name: replay-sanity_check-4.2 + - name: replay-go_test-4.2 + - name: replay-auth_test-4.2 + - name: replay-sharded_test-4.2 + - name: replay-repl_test-4.2 # Disabled due to TOOLS-2108 - # - name: replay-replay_test + # - name: replay-replay_test-4.2 ubuntu_x86_64_race_task_list: &ubuntu_x86_64_race_tasks - name: dist - - name: integration - - name: integration-auth + - name: integration-4.0 + - name: integration-4.0-auth + - name: integration-4.2 + - name: integration-4.2-auth - name: qa-tests-4.0 + - name: qa-tests-4.2 - name: unit - name: replay-dist - - name: replay-sanity_check - - name: replay-go_test - - name: replay-auth_test - - name: replay-sharded_test - - name: replay-repl_test + - name: replay-sanity_check-4.2 + - name: replay-go_test-4.2 + - name: replay-auth_test-4.2 + - name: replay-sharded_test-4.2 + - name: replay-repl_test-4.2 # Disabled due to TOOLS-2108 - # - name: replay-replay_test + # - name: replay-replay_test-4.2 windows_64_task_list: &windows_64_tasks - name: dist - - name: integration - - name: integration-auth + - name: integration-4.0 + - name: integration-4.0-auth + - name: integration-4.2 + - name: integration-4.2-auth distros: - windows-64-vs2013-test - name: qa-tests-3.2 @@ -174,13 +201,16 @@ mongo_tools_variables: - name: qa-tests-4.0 distros: - windows-64-vs2013-test - - name: qa-dump-restore-archiving + - name: qa-tests-4.2 + distros: + - windows-64-vs2013-test + - name: qa-dump-restore-archiving-4.2 distros: - windows-64-vs2013-test - name: qa-dump-restore-archiving-3.2 distros: - windows-64-vs2013-test - - name: qa-dump-restore-gzip + - name: qa-dump-restore-gzip-4.2 distros: - windows-64-vs2013-test - name: qa-dump-restore-gzip-3.2 @@ -190,16 +220,21 @@ mongo_tools_variables: - name: unit windows_64_ssl_task_list: &windows_64_ssl_tasks - name: dist - - name: integration - - name: integration-auth + - name: integration-4.0 + - name: integration-4.0-auth + - name: integration-4.2 + - name: integration-4.2-auth - name: qa-tests-4.0 + - name: qa-tests-4.2 - name: qa-tests-unstable - - name: native-cert-ssl + - name: native-cert-ssl-4.2 - name: unit windows_64_enterprise_task_list: &windows_64_enterprise_tasks - name: dist - - name: integration - - name: integration-auth + - name: integration-4.0 + - name: integration-4.0-auth + - name: integration-4.2 + - name: integration-4.2-auth - name: kerberos distros: - windows-64-vs2013-test @@ -215,63 +250,78 @@ mongo_tools_variables: - name: qa-tests-4.0 distros: - windows-64-vs2013-test + - name: qa-tests-4.2 + distros: + - windows-64-vs2013-test - name: qa-tests-unstable distros: - windows-64-vs2013-test - name: unit - - name: native-cert-ssl + - name: native-cert-ssl-4.2 rhel71_ppc64le_enterprise_task_list: &rhel71_ppc64le_enterprise_tasks - name: dist - - name: integration - - name: integration-auth + - name: integration-4.0 + - name: integration-4.0-auth + - name: integration-4.2 + - name: integration-4.2-auth #- name: kerberos - - name: qa-dump-restore-archiving - - name: qa-dump-restore-gzip + - name: qa-dump-restore-archiving-4.2 + - name: qa-dump-restore-gzip-4.2 - name: qa-tests-3.4 - name: qa-tests-3.6 - name: qa-tests-4.0 + - name: qa-tests-4.2 - name: qa-tests-unstable - - name: native-cert-ssl + - name: native-cert-ssl-4.2 - name: replay-dist - - name: replay-sanity_check - - name: replay-go_test - - name: replay-auth_test - - name: replay-sharded_test - - name: replay-repl_test + - name: replay-sanity_check-4.2 + - name: replay-go_test-4.2 + - name: replay-auth_test-4.2 + - name: replay-sharded_test-4.2 + - name: replay-repl_test-4.2 # Disabled due to TOOLS-2108 - # - name: replay-replay_test + # - name: replay-replay_test-4.2 rhel67_s390x_enterprise_task_list: &rhel67_s390x_enterprise_tasks - name: dist - - name: integration - - name: integration-auth + - name: integration-4.0 + - name: integration-4.0-auth + - name: integration-4.2 + - name: integration-4.2-auth # Disabled due to TOOLS-2119 # - name: kerberos - - name: qa-dump-restore-archiving - - name: qa-dump-restore-gzip + - name: qa-dump-restore-archiving-4.2 + - name: qa-dump-restore-gzip-4.2 - name: qa-tests-3.4 - name: qa-tests-3.6 - name: qa-tests-4.0 + - name: qa-tests-4.2 - name: qa-tests-unstable - - name: native-cert-ssl + - name: native-cert-ssl-4.2 - name: replay-dist - - name: replay-sanity_check - - name: replay-go_test - - name: replay-auth_test - - name: replay-sharded_test - - name: replay-repl_test + - name: replay-sanity_check-4.2 + - name: replay-go_test-4.2 + - name: replay-auth_test-4.2 + - name: replay-sharded_test-4.2 + - name: replay-repl_test-4.2 # Disabled due to TOOLS-2108 - # - name: replay-replay_test + # - name: replay-replay_test-4.2 ubuntu1604_arm64_ssl_task_list: &ubuntu1604_arm64_ssl_tasks - name: dist - - name: integration - - name: integration-auth - - name: qa-dump-restore-archiving - - name: qa-dump-restore-gzip + - name: integration-4.0 + - name: integration-4.0-auth - name: qa-tests-3.4 - name: qa-tests-3.6 - name: qa-tests-4.0 + - name: replay-dist + ubuntu1804_arm64_ssl_task_list: &ubuntu1804_arm64_ssl_tasks + - name: dist + - name: integration-4.2 + - name: integration-4.2-auth + - name: qa-dump-restore-archiving-4.2 + - name: qa-dump-restore-gzip-4.2 + - name: qa-tests-4.2 - name: qa-tests-unstable - - name: native-cert-ssl + - name: native-cert-ssl-4.2 - name: replay-dist @@ -938,7 +988,7 @@ tasks: vars: tool: mongotop -- name: integration +- name: integration-4.0 commands: - func: "fetch source" - command: expansions.update @@ -951,7 +1001,7 @@ tasks: vars: INT_TEST: "true" -- name: integration-auth +- name: integration-4.0-auth commands: - func: "fetch source" # Concat auth args @@ -976,6 +1026,44 @@ tasks: INT_TEST: "true" AUTH_TEST: "true" +- name: integration-4.2 + commands: + - func: "fetch source" + - command: expansions.update + - func: "download mongod" + vars: + mongo_version: "4.2" + - func: "start mongod" + - func: "wait for mongod to be ready" + - func: "run tool integration tests" + vars: + INT_TEST: "true" + +- name: integration-4.2-auth + commands: + - func: "fetch source" + # Concat auth args + - command: expansions.update + params: + updates: + - key: "mongod_args" + concat: " --auth" + - key: "auth_username" + value: "passwordIsTaco" + - key: "auth_password" + value: "Taco" + - key: "create_mongod_users_command" + value: "db.createUser({ user: '${auth_username}', pwd: '${auth_password}', roles: [{ role: '__system', db: 'admin' }] });" + - func: "download mongod" + vars: + mongo_version: "4.2" + - func: "start mongod" + - func: "wait for mongod to be ready" + - func: "run tool integration tests" + vars: + INT_TEST: "true" + AUTH_TEST: "true" + - name: kerberos commands: - func: "fetch source" @@ -1110,6 +1198,45 @@ tasks: resmoke_suite: "core${resmoke_use_ssl}" excludes: "requires_mongo_26,${excludes}" +- name: qa-tests-4.2 + depends_on: + - name: dist + commands: + - func: "fetch source" + - func: "get buildnumber" + - func: "setup credentials" + - func: "download mongod" + vars: + mongo_version: "4.2" + - func: "fetch tool" + vars: + tool: mongoimport + - func: "fetch tool" + vars: + tool: mongoexport + - func: "fetch tool" + vars: + tool: mongodump + - func: "fetch tool" + vars: + tool: mongorestore + - func: "fetch tool" + vars: + tool: mongostat + - func: "fetch tool" + vars: + tool: mongotop + - func: "fetch tool" + vars: + tool: mongofiles + - func: "fetch tool" + vars: + tool: bsondump + - func: "run qa-tests" + vars: + resmoke_suite: "core${resmoke_use_ssl}" + excludes: "requires_mongo_26,requires_unstable,${excludes}" + - name: qa-tests-4.0 depends_on: - name: dist @@ -1266,7 +1393,7 @@ tasks: resmoke_suite: "core${resmoke_use_ssl}" excludes: "requires_mongo_26,requires_mongo_34,requires_mongo_36,requires_mongo_40,requires_unstable,,${excludes}" -- name: native-cert-ssl +- name: native-cert-ssl-4.2 depends_on: - name: dist commands: @@ -1275,7 +1402,7 @@ tasks: - func: "setup credentials" - func: "download mongod" vars: - mongo_version: "4.0" + mongo_version: "4.2" - func: "fetch tool" vars: tool: mongoimport @@ -1313,7 +1440,7 @@ tasks: chmod 400 jstests/libs/key* python buildscripts/resmoke.py --suite=native_cert_ssl --continueOnFailure --log=buildlogger --reportFile=../../report.json ${resmoke_args} --excludeWithAnyTags="${excludes}" -- name: qa-dump-restore-archiving +- name: qa-dump-restore-archiving-4.2 depends_on: - name: dist commands: @@ -1322,7 +1449,7 @@ tasks: - func: "setup credentials" - func: "download mongod" vars: - mongo_version: "4.0" + mongo_version: "4.2" - func: "fetch tool" vars: tool: mongodump @@ -1355,7 +1482,7 @@ tasks: resmoke_suite: "restore_archive" excludes: "requires_mongo_26,requires_mongo_34,requires_mongo_36,requires_mongo_40,requires_unstable,${excludes}" -- name: qa-dump-restore-gzip +- name: qa-dump-restore-gzip-4.2 depends_on: - name: dist commands: @@ -1364,7 +1491,7 @@ tasks: - func: "setup credentials" - func: "download mongod" vars: - mongo_version: "4.0" + mongo_version: "4.2" - func: "fetch tool" vars: tool: mongodump @@ -1466,7 +1593,7 @@ tasks: tool: mongoreplay - func: "build tool" -- name: replay-sanity_check +- name: replay-sanity_check-4.2 depends_on: - name: replay-dist commands: @@ -1476,7 +1603,7 @@ tasks: tool: mongoreplay - func: "download mongod" vars: - mongo_version: "4.0" + mongo_version: "4.2" - func: "start mongod" - func: "wait for mongod to be ready" - command: shell.exec @@ -1490,7 +1617,7 @@ tasks: echo "Running sanity check" PATH=$PATH:$PWD/bin ./mongoreplay/sanity_check.sh -p ${mongod_port} -- name: replay-go_test +- name: replay-go_test-4.2 depends_on: - name: replay-dist commands: @@ -1506,7 +1633,7 @@ tasks: pcapFname: getmore_single_channel.pcap - func: "download mongod" vars: - mongo_version: "4.0" + mongo_version: "4.2" - func: "start mongod" - func: "wait for mongod to be ready" - func: "run replay go_test" @@ -1516,7 +1643,7 @@ tasks: additional_args: github.com/mongodb/mongo-tools/mongoreplay TESTING_REPLAY: true -- name: replay-sharded_test +- name: replay-sharded_test-4.2 depends_on: - name: replay-dist commands: @@ -1532,7 +1659,7 @@ tasks: pcapFname: getmore_single_channel.pcap - func: "download mongod" vars: - mongo_version: "4.0" + mongo_version: "4.2" - func: "create sharded_cluster" - func: "run replay go_test" vars: @@ -1541,7 +1668,7 @@ tasks: additional_args: github.com/mongodb/mongo-tools/mongoreplay --run "LiveDB" TESTING_REPLAY: true -- name: replay-auth_test +- name: replay-auth_test-4.2 depends_on: - name: replay-dist commands: @@ -1557,7 +1684,7 @@ tasks: pcapFname: getmore_single_channel.pcap - func: "download mongod" vars: - mongo_version: "4.0" + mongo_version: "4.2" - func: "start mongod" vars: additional_args: --auth @@ -1572,7 +1699,7 @@ tasks: additional_args: github.com/mongodb/mongo-tools/mongoreplay --run "(LiveDB)|(Authed)" TESTING_REPLAY: true -- name: replay-repl_test +- name: replay-repl_test-4.2 depends_on: - name: replay-dist commands: @@ -1588,7 +1715,7 @@ tasks: pcapFname: getmore_single_channel.pcap - func: "download mongod" vars: - mongo_version: "4.0" + mongo_version: "4.2" - func: "create repl_set" vars: mongod_port: ${mongod_port} @@ -1599,7 +1726,7 @@ tasks: additional_args: github.com/mongodb/mongo-tools/mongoreplay --run "LiveDB" TESTING_REPLAY: true -- name: replay-replay_test +- name: replay-replay_test-4.2 depends_on: - name: replay-dist commands: @@ -1609,7 +1736,7 @@ tasks: tool: mongoreplay - func: "download mongod" vars: - mongo_version: "4.0" + mongo_version: "4.2" - func: "fetch ftdc" - command: shell.exec params: @@ -2024,6 +2151,7 @@ buildvariants: # ARM Buildvariants # ####################################### +# MongoDB 3.4 - 4.0 - name: ubuntu1604-arm64-ssl display_name: ZAP ARM64 Ubuntu 16.04 SSL run_on: @@ -2046,6 +2174,29 @@ buildvariants: USE_SSL: "true" tasks: *ubuntu1604_arm64_ssl_tasks +# MongoDB 4.2+ +- name: ubuntu1804-arm64-ssl + display_name: ZAP ARM64 Ubuntu 18.04 SSL + run_on: + - ubuntu1804-arm64-test + stepback: false + batchtime: 10080 # weekly + expansions: + <<: *mongod_default_startup_args + <<: *mongo_default_startup_args + mongo_os: "ubuntu1804" + mongo_edition: "targeted" + mongo_arch: "aarch64" + build_tags: "ssl" + resmoke_use_ssl: _ssl + excludes: requires_mmap_available,requires_large_ram,requires_mongo_24,requires_mongo_26,requires_mongo_30 + resmoke_args: -j 2 + arch: "linux/arm64" + edition: ssl + integration_test_args: integration + USE_SSL: "true" + tasks: *ubuntu1804_arm64_ssl_tasks + ####################################### # Power Buildvariants # ####################################### @@ -2072,6 +2223,7 @@ buildvariants: integration_test_args: integration tasks: *rhel71_ppc64le_enterprise_tasks +# MongoDB 3.4 - 4.0 - name: ubuntu1604-ppc64le-enterprise display_name: ZAP PPC64LE Ubuntu 16.04 Enterprise run_on: @@ -2084,6 +2236,19 @@ buildvariants: - name: dist - name: replay-dist +# MongoDB 4.2+ +- name: ubuntu1804-ppc64le-enterprise + display_name: ZAP PPC64LE Ubuntu 18.04 Enterprise + run_on: + - ubuntu1804-power8-test + stepback: false + batchtime: 10080 # weekly + expansions: + build_tags: 'ssl sasl gssapi' + tasks: + - name: dist + - name: replay-dist + ####################################### # Z (s390x) Buildvariants # ####################################### @@ -2122,6 +2287,18 @@ buildvariants: - name: dist - name: replay-dist +- name: ubuntu1804-s390x-enterprise + display_name: ZAP s390x Ubuntu 18.04 Enterprise + run_on: + - ubuntu1804-zseries-test + stepback: false + batchtime: 10080 # weekly + expansions: + build_tags: "sasl gssapi ssl" + tasks: + - name: dist + - name: replay-dist + ####################################### # Experimental Buildvariants # ####################################### diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/import.data b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/import.data index e3a82705d12..24abf8f7dec 100644 --- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/import.data +++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/import.data @@ -1,5 +1,5 @@ { - "commit": "25f23659be74d2f882ead1a9882b66872214f369", + "commit": "d7cc167b3f43f7264b6e4350a1632dd730793d6b", "github": "mongodb/mongo-tools.git", "vendor": "tools", "branch": "v4.1" diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/fixtures_test.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/fixtures_test.go new file mode 100644 index 00000000000..d04b61ff2d9 --- /dev/null +++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/fixtures_test.go @@ -0,0 +1,167 @@ +// Copyright (C) MongoDB, Inc. 2019-present. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +package mongorestore + +import ( + "fmt" + "os" + "path" + "path/filepath" + "strings" + + "github.com/mongodb/mongo-tools-common/db" + "github.com/mongodb/mongo-tools/legacy/util" + "go.mongodb.org/mongo-driver/bson" +) + +type testCollData struct { + ns string + docs []bson.D + metadata bson.D +} + +func (tcd testCollData) SplitNS() (string, string) { + ns := strings.SplitN(tcd.ns, ".", 2) + if len(ns) != 2 { + panic(fmt.Sprintf("invalid namespace '%s'", tcd.ns)) + } + return ns[0], util.EscapeCollectionName(ns[1]) +} + +func (tcd testCollData) Mkdir(basePath string) error { + db, _ := tcd.SplitNS() + dbDir := path.Join(basePath, db) + err := os.MkdirAll(dbDir, 0755) + if err != nil { + return err + } + return nil +} + +func (tcd testCollData) WriteData(basePath string) error { + db, coll := tcd.SplitNS() + file, err := os.Create(path.Join(basePath, db, coll+".bson")) + if err != nil { + return err + } + defer file.Close() + + for _, doc := range tcd.docs { + raw, err := bson.Marshal(doc) + if err != nil { + return err + } + _, err = file.Write(raw) + if err != nil { + return err + } + } + + return file.Sync() +} + +func (tcd testCollData) WriteMetadata(basePath string) error { + if tcd.metadata == nil { + return nil + } + + db, coll := tcd.SplitNS() + file, err := os.Create(path.Join(basePath, db, coll+".metadata.json")) + if err != nil { + return err + } + defer file.Close() + + raw, err := bson.MarshalExtJSON(tcd.metadata, true, false) + if err != nil { + return err + } + _, err = file.Write(raw) + if err != nil { + return err + } + + return file.Sync() +} + +type testDumpDir struct { + dirName string + oplog []db.Oplog + collections []testCollData +} + +func (tdd *testDumpDir) Create() error { + + err := tdd.Cleanup() + if err != nil { + return err + } + + err = os.MkdirAll(tdd.Path(), 0755) + if err != nil { + return err + } + + for _, coll := range tdd.collections { + err := coll.Mkdir(tdd.Path()) + if err != nil { + return err + } + err = coll.WriteData(tdd.Path()) + if err != nil { + return err + } + err = coll.WriteMetadata(tdd.Path()) + if err != nil { + return err + } + } + + err = tdd.WriteOplog() + if err != nil { + return err + } + + return nil +} + +// Cleanup removes the test directory unless "NO_CLEANUP" is set in the environment. +func (tdd *testDumpDir) Cleanup() error { + noCleanup := os.Getenv("NO_CLEANUP") + if noCleanup == "0" { + return nil + } + return os.RemoveAll(tdd.Path()) +} + +func (tdd *testDumpDir) WriteOplog() error { + if tdd.oplog == nil { + return nil + } + file, err := os.Create(path.Join(tdd.Path(), "oplog.bson")) + if err != nil { + return err + } + defer file.Close() + + for _, op := range tdd.oplog { + raw, err := bson.Marshal(op) + if err != nil { + return err + } + _, err = file.Write(raw) + if err != nil { + return err + } + } + + return file.Sync() +} + +func (tdd *testDumpDir) Path() string { + return filepath.Join("testdata", tdd.dirName) +} diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/metadata.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/metadata.go index b2555c64d6e..dd3c657e687 100644 --- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/metadata.go +++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/metadata.go @@ -146,7 +146,7 @@ func (restore *MongoRestore) CollectionExists(intent *intents.Intent) (bool, err // CreateIndexes takes in an intent and an array of index documents and // attempts to create them using the createIndexes command. If that command // fails, we fall back to individual index creation. -func (restore *MongoRestore) CreateIndexes(intent *intents.Intent, indexes []IndexDocument) error { +func (restore *MongoRestore) CreateIndexes(intent *intents.Intent, indexes []IndexDocument, hasNonSimpleCollation bool) error { // first, sanitize the indexes for _, index := range indexes { // update the namespace of the index before inserting @@ -165,6 +165,12 @@ func (restore *MongoRestore) CreateIndexes(intent *intents.Intent, indexes []Ind if !restore.OutputOptions.KeepIndexVersion { delete(index.Options, "v") } + + // for non-simple default collation on the collection, indexes without + // a collation option need to add "collation:{locale:"simple"}} + if _, ok := index.Options["collation"]; hasNonSimpleCollation && !ok { + index.Options["collation"] = bson.D{{"locale", "simple"}} + } } session, err := restore.SessionProvider.GetSession() diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/metadata_test.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/metadata_test.go index a5670174d59..f11a842e944 100644 --- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/metadata_test.go +++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/metadata_test.go @@ -7,6 +7,8 @@ package mongorestore import ( + "fmt" + "io/ioutil" "testing" "github.com/mongodb/mongo-tools-common/intents" @@ -179,3 +181,52 @@ func TestGetDumpAuthVersion(t *testing.T) { }) } + +const indexCollationTestDataFile = "testdata/index_collation.json" + +func TestIndexGetsSimpleCollation(t *testing.T) { + testtype.SkipUnlessTestType(t, testtype.IntegrationTestType) + + metadata, err := readCollationTestData(indexCollationTestDataFile) + if err != nil { + t.Fatalf("Error reading data file: %v", err) + } + + dumpDir := testDumpDir{ + dirName: "index_collation", + collections: []testCollData{{ + ns: "test.foo", + metadata: metadata, + }}, + } + + err = dumpDir.Create() + if err != nil { + t.Fatalf("Error reading data file: %v", err) + } + + Convey("With a test MongoRestore", t, func() { + args := []string{ + DropOption, + dumpDir.Path(), + } + restore, err := getRestoreWithArgs(args...) + So(err, ShouldBeNil) + + result := restore.Restore() + So(result.Err, ShouldBeNil) + }) +} + +func readCollationTestData(filename string) (bson.D, error) { + b, err := ioutil.ReadFile(filename) + if err != nil { + return nil, fmt.Errorf("couldn't load %s: %v", filename, err) + } + var data bson.D + err = bson.UnmarshalExtJSON(b, false, &data) + if err != nil { + return nil, fmt.Errorf("couldn't decode JSON: %v", err) + } + return data, nil +} diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/oplog.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/oplog.go index 4d76079d290..a24f316bf38 100644 --- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/oplog.go +++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/oplog.go @@ -178,11 +178,16 @@ func (restore *MongoRestore) filterUUIDs(op db.Oplog) (db.Oplog, error) { if !restore.OutputOptions.PreserveUUID { op.UI = nil + // TODO TOOLS-2308: the following workaround is no longer allowed since + // 4.1.3 and no longer needed since 3.6.9/4.0.3. We're commenting it + // out to get our CI to green, but need a longer-term fix for users on + // 3.0.0-3.0.8/4.0.0-4.0.2. + // new createIndexes oplog command requires 'ui', so if we aren't // preserving UUIDs, we must convert it to an old style index insert - if op.Operation == "c" && op.Object[0].Key == "createIndexes" { - return convertCreateIndexToIndexInsert(op) - } + // if op.Operation == "c" && op.Object[0].Key == "createIndexes" { + // return convertCreateIndexToIndexInsert(op) + // } } // Check for and filter nested applyOps ops diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/restore.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/restore.go index fb28c144485..1ddc7b639f0 100644 --- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/restore.go +++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/mongorestore/restore.go @@ -12,6 +12,7 @@ import ( "strings" "time" + "github.com/mongodb/mongo-tools-common/bsonutil" "github.com/mongodb/mongo-tools-common/db" "github.com/mongodb/mongo-tools-common/intents" "github.com/mongodb/mongo-tools-common/log" @@ -184,6 +185,7 @@ func (restore *MongoRestore) RestoreIntent(intent *intents.Intent) Result { } logMessageSuffix := "with no metadata" + var hasNonSimpleCollation bool // first create the collection with options from the metadata file if intent.MetadataFile != nil { logMessageSuffix = "using options from metadata" @@ -211,6 +213,14 @@ func (restore *MongoRestore) RestoreIntent(intent *intents.Intent) Result { } uuid = metadata.UUID } + + collation, err := bsonutil.FindSubdocumentByKey("collation", &options) + if err == nil { + localeValue, err := bsonutil.FindValueByKey("locale", &collation) + if err == nil { + hasNonSimpleCollation = localeValue != "simple" + } + } } // The only way to specify options on the idIndex is at collection creation time. @@ -279,7 +289,7 @@ func (restore *MongoRestore) RestoreIntent(intent *intents.Intent) Result { // finally, add indexes if len(indexes) > 0 && !restore.OutputOptions.NoIndexRestore { log.Logvf(log.Always, "restoring indexes for collection %v from metadata", intent.Namespace()) - err = restore.CreateIndexes(intent, indexes) + err = restore.CreateIndexes(intent, indexes, hasNonSimpleCollation) if err != nil { result.Err = fmt.Errorf("error creating indexes for %v: %v", intent.Namespace(), err) return result diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/bsonutil/bsonutil.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/bsonutil/bsonutil.go index ab7f28313bf..020fa9a78b1 100644 --- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/bsonutil/bsonutil.go +++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/bsonutil/bsonutil.go @@ -63,7 +63,7 @@ func GetExtendedBsonD(doc bson.D) (bson.D, error) { return nil, err } bsonDoc = append(bsonDoc, bson.E{ - Key: docElem.Key, + Key: docElem.Key, Value: bsonValue, }) } @@ -81,6 +81,40 @@ func FindValueByKey(keyName string, document *bson.D) (interface{}, error) { return nil, ErrNoSuchField } +// FindIntByKey returns the value of keyName in the document as an int for +// either int32 or int64 underlying type. +func FindIntByKey(keyName string, document *bson.D) (int, error) { + raw, err := FindValueByKey(keyName, document) + if err != nil { + return 0, err + } + switch x := raw.(type) { + case int32: + return int(x), nil + case int64: + return int(x), nil + case int: + return x, nil + default: + return 0, fmt.Errorf("field '%s' is not an integer type", keyName) + } +} + +// FindSubdocumentByKey returns the value of keyName in document as a document. +// Returns an error if keyName is not found in the top-level of the document, +// or if it is found but its value is not a document. +func FindSubdocumentByKey(keyName string, document *bson.D) (bson.D, error) { + value, err := FindValueByKey(keyName, document) + if err != nil { + return bson.D{}, err + } + doc, ok := value.(bson.D) + if !ok { + return bson.D{}, fmt.Errorf("field '%s' is not a document", keyName) + } + return doc, nil +} + // ParseSpecialKeys takes a JSON document and inspects it for any extended JSON // type (e.g $numberLong) and replaces any such values with the corresponding // BSON type. (uses legacy extJSON parser) diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/db/db.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/db/db.go index dde6bf2cc63..7537a48ef5b 100644 --- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/db/db.go +++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/db/db.go @@ -92,14 +92,17 @@ type ApplyOpsResponse struct { // Oplog represents a MongoDB oplog document. type Oplog struct { - Timestamp primitive.Timestamp `bson:"ts"` - HistoryID int64 `bson:"h"` - Version int `bson:"v"` - Operation string `bson:"op"` - Namespace string `bson:"ns"` - Object bson.D `bson:"o"` - Query bson.D `bson:"o2"` - UI *primitive.Binary `bson:"ui,omitempty"` + Timestamp primitive.Timestamp `bson:"ts"` + HistoryID int64 `bson:"h"` + Version int `bson:"v"` + Operation string `bson:"op"` + Namespace string `bson:"ns"` + Object bson.D `bson:"o"` + Query bson.D `bson:"o2,omitempty"` + UI *primitive.Binary `bson:"ui,omitempty"` + LSID bson.Raw `bson:"lsid,omitempty"` + TxnNumber *int64 `bson:"txnNumber,omitempty"` + PrevOpTime bson.Raw `bson:"prevOpTime,omitempty"` } // Returns a mongo.Client connected to the database server for which the diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/testutil/testutil.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/testutil/testutil.go index 342876520cb..561858044a6 100644 --- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/testutil/testutil.go +++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/testutil/testutil.go @@ -8,6 +8,7 @@ package testutil import ( + "math/rand" "os" "strconv" "strings" @@ -137,3 +138,32 @@ func dottedStringToSlice(s string) ([]int, error) { } return parts, nil } + +// MergeOplogStreams combines oplog arrays such that the order of entries is +// random, but order-preserving with respect to each initial stream. +func MergeOplogStreams(input [][]db.Oplog) []db.Oplog { + // Copy input op arrays so we can destructively shuffle them together + streams := make([][]db.Oplog, len(input)) + opCount := 0 + for i, v := range input { + streams[i] = make([]db.Oplog, len(v)) + copy(streams[i], v) + opCount += len(v) + } + + ops := make([]db.Oplog, 0, opCount) + for len(streams) != 0 { + // randomly pick a stream to add an op + rand.Shuffle(len(streams), func(i, j int) { + streams[i], streams[j] = streams[j], streams[i] + }) + ops = append(ops, streams[0][0]) + // remove the op and its stream if empty + streams[0] = streams[0][1:] + if len(streams[0]) == 0 { + streams = streams[1:] + } + } + + return ops +} diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/txn/buffer.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/txn/buffer.go new file mode 100644 index 00000000000..2add53b5f9b --- /dev/null +++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/txn/buffer.go @@ -0,0 +1,354 @@ +// Copyright (C) MongoDB, Inc. 2019-present. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +// Package txn implements functions for examining and processing transaction +// oplog entries. +package txn + +import ( + "errors" + "fmt" + "sync" + + "github.com/mongodb/mongo-tools-common/bsonutil" + "github.com/mongodb/mongo-tools-common/db" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" +) + +var ErrBufferClosed = errors.New("transaction buffer already closed") +var ErrTxnAborted = errors.New("transaction aborted") +var ErrNotTransaction = errors.New("oplog entry is not a transaction") + +type txnTask struct { + meta Meta + op db.Oplog +} + +// txnState tracks an individual transaction, including storage of related ops +// and communication channels. It includes a WaitGroup for waiting on +// transaction-related goroutines. +type txnState struct { + buffer []db.Oplog + ingestChan chan txnTask + ingestDone chan struct{} + ingestErr error + stopChan chan struct{} + wg sync.WaitGroup +} + +func newTxnState() *txnState { + return &txnState{ + ingestChan: make(chan txnTask), + ingestDone: make(chan struct{}), + stopChan: make(chan struct{}), + buffer: make([]db.Oplog, 0), + } +} + +// Because state is currently kept in memory, purge merely drops the reference +// so the GC will eventually clean up. Eventually, this might clean up a file +// on disk. +func (ts *txnState) purge() error { + ts.buffer = nil + return nil +} + +// Buffer stores transaction oplog entries until they are needed +// to commit them to a desination. It includes a WaitGroup for tracking +// all goroutines across all transactions for use in global shutdown. +type Buffer struct { + sync.Mutex + stopped bool + txns map[ID]*txnState + wg sync.WaitGroup +} + +// NewBuffer initializes a transaction oplog buffer. +func NewBuffer() *Buffer { + return &Buffer{ + txns: make(map[ID]*txnState), + } +} + +// Concurrency notes: +// +// We require that AddOp, GetTxnStream and PurgeTxn be called serially as part +// of orchestrating replay of oplog entries. The only method that could run +// concurrently is Stop. If Stop is called, we're in some sort of global +// shutdown, so we don't care how other methods and goroutines resolve, only +// that they do so without panicking. +// + +// AddOp sends a transaction oplog entry to a background goroutine (starting +// one for a new transaction ID) for asynchronous pre-processing and storage. +// If the oplog entry is not a transaction, an error will be returned. Any +// errors during processing can be discovered later via the error channel from +// `GetTxnStream`. +// +// Must not be called concurrently with other transaction-related operations. +// Must not be called for a given transaction after starting to stream that +// transaction. +func (b *Buffer) AddOp(m Meta, op db.Oplog) error { + b.Lock() + defer b.Unlock() + + if b.stopped { + return ErrBufferClosed + } + + if !m.IsTxn() { + return ErrNotTransaction + } + + // Get or initialize transaction state + state, ok := b.txns[m.id] + if !ok { + state = newTxnState() + b.txns[m.id] = state + b.wg.Add(1) + state.wg.Add(1) + go b.ingester(state) + } + + // Send unless the ingester has shut down, e.g. on error + select { + case <-state.ingestDone: + case state.ingestChan <- txnTask{meta: m, op: op}: + } + + return nil +} + +func (b *Buffer) ingester(state *txnState) { +LOOP: + for { + select { + case t := <-state.ingestChan: + if t.meta.IsData() { + // process it + innerOps, err := extractInnerOps(t.op.Object) + if err != nil { + state.ingestErr = err + break LOOP + } + // store it + for _, op := range innerOps { + state.buffer = append(state.buffer, op) + } + } + if t.meta.IsFinal() { + break LOOP + } + case <-state.stopChan: + break LOOP + } + } + close(state.ingestDone) + state.wg.Done() + b.wg.Done() +} + +// GetTxnStream returns a channel of Oplog entries in a transaction and a +// channel for errors. If the buffer has been stopped, the returned op channel +// will be closed and the error channel will have an error on it. +// +// Must not be called concurrently with other transaction-related operations. +// For a given transaction, it must not be called until after a final oplog +// entry has been passed to AddOp and it must not be called more than once. +func (b *Buffer) GetTxnStream(m Meta) (<-chan db.Oplog, <-chan error) { + b.Lock() + defer b.Unlock() + + opChan := make(chan db.Oplog) + errChan := make(chan error, 1) + + if b.stopped { + return sendErrAndClose(opChan, errChan, ErrBufferClosed) + } + + if !m.IsTxn() { + return sendErrAndClose(opChan, errChan, ErrNotTransaction) + } + + state := b.txns[m.id] + if state == nil { + return sendErrAndClose(opChan, errChan, fmt.Errorf("GetTxnStream found no state for %v", m.id)) + } + + // The final oplog entry must have been passed to AddOp before calling this + // method, so we know this will be able to make progress. + <-state.ingestDone + + if state.ingestErr != nil { + return sendErrAndClose(opChan, errChan, state.ingestErr) + } + + // Launch streaming goroutine + b.wg.Add(1) + state.wg.Add(1) + go b.streamer(state, opChan, errChan) + + return opChan, errChan +} + +func (b *Buffer) streamer(state *txnState, opChan chan<- db.Oplog, errChan chan<- error) { +LOOP: + for _, op := range state.buffer { + select { + case opChan <- op: + case <-state.stopChan: + errChan <- ErrTxnAborted + break LOOP + } + } + close(opChan) + close(errChan) + state.wg.Done() + b.wg.Done() +} + +// PurgeTxn closes any transaction streams in progress and deletes all oplog +// entries associated with a transaction. +// +// Must not be called concurrently with other transaction-related operations. +// For a given transaction, it must not be called until after a final oplog +// entry has been passed to AddOp and it must not be called more than once. +func (b *Buffer) PurgeTxn(m Meta) error { + b.Lock() + defer b.Unlock() + if b.stopped { + return ErrBufferClosed + } + state := b.txns[m.id] + if state == nil { + return fmt.Errorf("PurgeTxn found no state for %v", m.id) + } + + // When the lock is dropped, we don't want Stop to find this transaction and + // double-close it. + delete(b.txns, m.id) + close(state.stopChan) + + // Wait for goroutines to terminate, then clean up. + state.wg.Wait() + state.purge() + + return nil +} + +// Stop shuts down processing and cleans up. Subsequent calls to Stop() will return nil. +// All other methods error after this is called. +func (b *Buffer) Stop() error { + b.Lock() + if b.stopped { + b.Unlock() + return nil + } + + b.stopped = true + for _, state := range b.txns { + close(state.stopChan) + } + + b.Unlock() + + // At this point we know any subsequent public method will see the buffer + // is stopped, no new goroutines will be launched, and existing goroutines + // have been signaled to close. Next, wait for goroutines to stop, then + // clean up. + + b.wg.Wait() + var firstErr error + for _, state := range b.txns { + err := state.purge() + if err != nil && firstErr == nil { + firstErr = err + } + } + + return firstErr +} + +// sendErrAndClose is a utility for putting an error on a channel before closing. +func sendErrAndClose(o chan db.Oplog, e chan error, err error) (chan db.Oplog, chan error) { + e <- err + close(o) + close(e) + return o, e +} + +const extractErrorFmt = "error extracting transaction ops: %s: %v" + +func extractInnerOps(doc bson.D) ([]db.Oplog, error) { + rawAO, err := bsonutil.FindValueByKey("applyOps", &doc) + if err != nil { + return nil, fmt.Errorf(extractErrorFmt, "applyOps field", err) + } + + ao, ok := rawAO.(bson.A) + if !ok { + return nil, fmt.Errorf(extractErrorFmt, "applyOps field", "not a BSON array") + } + + ops := make([]db.Oplog, len(ao)) + for i, v := range ao { + opDoc, ok := v.(bson.D) + if !ok { + return nil, fmt.Errorf(extractErrorFmt, "applyOps op", "not a BSON document") + } + op, err := bsonDocToOplog(opDoc) + if err != nil { + return nil, fmt.Errorf(extractErrorFmt, "applyOps op", err) + } + ops[i] = *op + } + + return ops, nil +} + +const opConvertErrorFmt = "error converting bson.D to op: %s: %v" + +func bsonDocToOplog(doc bson.D) (*db.Oplog, error) { + op := db.Oplog{} + + for _, v := range doc { + switch v.Key { + case "op": + s, ok := v.Value.(string) + if !ok { + return nil, fmt.Errorf(opConvertErrorFmt, "op field", "not a string") + } + op.Operation = s + case "ns": + s, ok := v.Value.(string) + if !ok { + return nil, fmt.Errorf(opConvertErrorFmt, "ns field", "not a string") + } + op.Namespace = s + case "o": + d, ok := v.Value.(bson.D) + if !ok { + return nil, fmt.Errorf(opConvertErrorFmt, "o field", "not a BSON Document") + } + op.Object = d + case "o2": + d, ok := v.Value.(bson.D) + if !ok { + return nil, fmt.Errorf(opConvertErrorFmt, "o2 field", "not a BSON Document") + } + op.Query = d + case "ui": + u, ok := v.Value.(primitive.Binary) + if !ok { + return nil, fmt.Errorf(opConvertErrorFmt, "ui field", "not binary data") + } + op.UI = &u + } + } + + return &op, nil +} diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/txn/meta.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/txn/meta.go new file mode 100644 index 00000000000..549872010b1 --- /dev/null +++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/mongodb/mongo-tools-common/txn/meta.go @@ -0,0 +1,115 @@ +// Copyright (C) MongoDB, Inc. 2019-present. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +package txn + +import ( + "encoding/base64" + "fmt" + + "github.com/mongodb/mongo-tools-common/db" +) + +// "empty" prevOpTime is {ts: Timestamp(0, 0), t: NumberLong(-1)} as BSON. +var emptyPrev = string([]byte{ + 28, 0, 0, 0, 17, 116, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 18, 116, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, +}) + +// ID wraps fields needed to uniquely identify a transaction for use as a map +// key. The 'lsid' is a string rather than bson.Raw or []byte so that this +// type is a valid map key. +type ID struct { + lsid string + txnNumber int64 +} + +func (id ID) String() string { + return fmt.Sprintf("%s-%d", base64.RawStdEncoding.EncodeToString([]byte(id.lsid)), id.txnNumber) +} + +// Meta holds information extracted from an oplog entry for later routing +// logic. Zero value means 'not a transaction'. We store 'prevOpTime' as +// string so the struct is comparable. +type Meta struct { + id ID + commit bool + abort bool + partial bool + prepare bool + prevOpTime string +} + +// NewMeta extracts transaction metadata from an oplog entry. A +// non-transaction will return a zero-value Meta struct, not an error. +// +// Currently there is no way for this to error, but that may change in the +// future if we change the db.Oplog.Object to bson.Raw, so the API is designed +// with failure as a possibility. +func NewMeta(op db.Oplog) (Meta, error) { + if op.LSID == nil { + return Meta{}, nil + } + + // Default prevOpTime to empty to "upgrade" 4.0 transactions without it. + m := Meta{ + id: ID{lsid: string(op.LSID), txnNumber: *op.TxnNumber}, + prevOpTime: emptyPrev, + } + + if op.PrevOpTime != nil { + m.prevOpTime = string(op.PrevOpTime) + } + + for _, e := range op.Object { + switch e.Key { + case "commitTransaction": + m.commit = true + case "abortTransaction": + m.abort = true + case "partialTxn": + m.partial = true + case "prepare": + m.prepare = true + } + } + + return m, nil +} + +// IsAbort is true if the oplog entry had the abort command. +func (m Meta) IsAbort() bool { + return m.abort +} + +// IsData is true if the oplog entry contains transaction data +func (m Meta) IsData() bool { + return !m.commit && !m.abort +} + +// IsCommit is true if the oplog entry was an abort command or was the +// final entry of an unprepared transaction. +func (m Meta) IsCommit() bool { + return m.commit || (m.IsTxn() && !m.prepare && !m.partial) +} + +// IsFinal is true if the oplog entry is the closing entry of a transaction, +// i.e. if IsAbort or IsCommit is true. +func (m Meta) IsFinal() bool { + return m.IsCommit() || m.IsAbort() +} + +// IsMultiOp is true if the oplog entry is part of a prepared and/or large +// transaction. +func (m Meta) IsMultiOp() bool { + return m.partial || m.prepare || (m.IsTxn() && m.prevOpTime != emptyPrev) +} + +// IsTxn is true if the oplog entry is part of any transaction, i.e. the lsid field +// exists. +func (m Meta) IsTxn() bool { + return m != Meta{} +} |