-
-
Notifications
You must be signed in to change notification settings - Fork 678
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
compilepkg: fix race when run without sandbox #3145
compilepkg: fix race when run without sandbox #3145
Conversation
a2b9cb7
to
80312f5
Compare
8d25896
to
7e75b42
Compare
e1a17c4
to
8e809f5
Compare
This PR is ready for review. The detail contexts is shared in #3144 |
Merged latest master into this PR to resolve the upstream merge-conflict |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the fix. It also make the Windows CI on rules_go more stable. Minor suggestions
On platforms without sandbox execution support such as Windows, multiple go_test targets declared in the same package would cause a race condition. ``` [ go_library( name = "same_package_{}".format(i), srcs = ["same_package.go"], importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/same_package_{}".format(i), x_defs = { "name": "{}".format(i), }, ) for i in range(1, 80) ] [ go_test( name = "same_package_{}_test".format(i), srcs = ["same_package_test.go"], embed = [":same_package_{}".format(i)], ) for i in range(1, 80) ] ``` For each of go_test targets, there would be internal archive and external archive that needs to compile from source files. However, due to testfilter, external archive would end up without any Go source and thus compilepkg needs to generate a dummy source file `_empty.go` to trick 'go tool compile'. This `_empty.go` file is generated in the output path of the Bazel package thus multiple go_test targets in the same package would generate this file using the same path. On a sandbox supported platform, this is not a problem as the full path is prefixed with the sandbox root dir. However, without sandbox, the full path is the same for each go_test's external archive compilation, leading to a race condition where multiple compilations running in parallel would compete to create/delete the same file. Fix this by using the unique importPath to create a directory to store the _empty.go file. This would effectively give each go_test compilation it's own _empty.go file in non-sandbox environment. Worth to note that in current solution, we still have yet to solve problem when 'importPath' is not provided. For example, in a setup like this where `go_library` does not exist, `importPath` will be blank and thus causes similar issues on non-sandbox platforms. ``` [ go_test( name = "same_package_{}_test".format(i), srcs = ["same_package_test.go"], ) for i in range(1, 80) ] ``` Although this is a valid use case, we recommend avoid setting up tests this way. Instead, you could setup a single go_test target with multiple shards to achieve similar result: ``` go_test( name = "same_package_{}_test".format(i), srcs = ["same_package_test.go"], shard_count = 80, ) ``` For more information, please review Bazel Test Sharding documentation(1) (1): https://docs.bazel.build/versions/main/test-encyclopedia.html#test-sharding
Adding a handy test_suite to run all the generated tests easily during development.
ef1c8c8
to
16069ac
Compare
Make use of the unique label's name constraints instead of relying on import path, which may be empty for packages with test only.
Looks like all CI have passed @linzhp PTAL 🙏 |
A suggestion from @linzhp during code review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@linzhp I don't have write access yet, could you do the merge if you are satisfied with the PR?
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [io_bazel_rules_go](https://togithub.com/bazelbuild/rules_go) | http_archive | minor | `v0.32.0` -> `v0.33.0` | --- ### Release Notes <details> <summary>bazelbuild/rules_go</summary> ### [`v0.33.0`](https://togithub.com/bazelbuild/rules_go/releases/tag/v0.33.0) [Compare Source](https://togithub.com/bazelbuild/rules_go/compare/v0.32.0...v0.33.0) ##### Breaking changes - [cover](https://togithub.com/bazelbuild/rules_go/blob/master/go/toolchains.rst#cover) has been removed in v0.32.0. Please [leave a comment](https://togithub.com/bazelbuild/rules_go/issues/3168) if you are affected by this. ##### Deprecations - The [asm](https://togithub.com/bazelbuild/rules_go/blob/master/go/toolchains.rst#asm), [compile](https://togithub.com/bazelbuild/rules_go/blob/master/go/toolchains.rst#compile), and [pack](https://togithub.com/bazelbuild/rules_go/blob/master/go/toolchains.rst#pack) action generators provided by [go_context](https://togithub.com/bazelbuild/rules_go/blob/master/go/toolchains.rst#go_context) are deprecated and planned for removal in version v0.36.0. Please leave a comment on the [tracking bug](https://togithub.com/bazelbuild/rules_go/issues/3168) if [archive](https://togithub.com/bazelbuild/rules_go/blob/master/go/toolchains.rst#archive) and [link](https://togithub.com/bazelbuild/rules_go/blob/master/go/toolchains.rst#link) are not suitable replacements for your use cases. ##### Bug Fixes - [@​sluongng](https://togithub.com/sluongng) fixed a race condition that could cause non-sandboxed builds of `go_test` targets to fail ([https://github.com/bazelbuild/rules_go/pull/3145](https://togithub.com/bazelbuild/rules_go/pull/3145)) - [@​abhinav](https://togithub.com/abhinav) made `//go:embed` work with `go_path` ([https://github.com/bazelbuild/rules_go/pull/3163](https://togithub.com/bazelbuild/rules_go/pull/3163)) - [@​xytan0056](https://togithub.com/xytan0056) made gopackagesdriver work with Go 1.18 ([https://github.com/bazelbuild/rules_go/pull/3157](https://togithub.com/bazelbuild/rules_go/pull/3157)) - [@​nickgooding](https://togithub.com/nickgooding) ensured that `gomock` can be used with any Gazelle naming convention ([https://github.com/bazelbuild/rules_go/pull/3155](https://togithub.com/bazelbuild/rules_go/pull/3155)) - `go_library` targets using CGo can now reference unresolved symbols ([https://github.com/bazelbuild/rules_go/pull/3174](https://togithub.com/bazelbuild/rules_go/pull/3174)) Thanks to all of the contributors! ##### Compatibility The minimum required version of Bazel remains at 4.2.1. ##### Updated dependencies - Updated `org_golang_x_sys`, `org_golang_x_xerrors`, `org_golang_google_genproto`, `go_googleapis` to their most recent commit as of 2022-06-05 As always, you can use higher versions of rules_go's dependencies by declaring them in WORKSPACE before calling go_rules_dependencies. Lower versions may work but are not supported. ##### `WORKSPACE` code load("@​bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "685052b498b6ddfe562ca7a97736741d87916fe536623afb7da2824c0211c369", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.33.0/rules_go-v0.33.0.zip", "https://github.com/bazelbuild/rules_go/releases/download/v0.33.0/rules_go-v0.33.0.zip", ], ) load("@​io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") go_rules_dependencies() go_register_toolchains(version = "1.18.3") </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, click this checkbox. --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/gapic-generator-go).
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [io_bazel_rules_go](https://togithub.com/bazelbuild/rules_go) | http_archive | minor | `v0.32.0` -> `v0.33.0` | --- ### Release Notes <details> <summary>bazelbuild/rules_go</summary> ### [`v0.33.0`](https://togithub.com/bazelbuild/rules_go/releases/tag/v0.33.0) [Compare Source](https://togithub.com/bazelbuild/rules_go/compare/v0.32.0...v0.33.0) #### Breaking changes - [cover](https://togithub.com/bazelbuild/rules_go/blob/master/go/toolchains.rst#cover) has been removed in v0.32.0. Please [leave a comment](https://togithub.com/bazelbuild/rules_go/issues/3168) if you are affected by this. #### Deprecations - The [asm](https://togithub.com/bazelbuild/rules_go/blob/master/go/toolchains.rst#asm), [compile](https://togithub.com/bazelbuild/rules_go/blob/master/go/toolchains.rst#compile), and [pack](https://togithub.com/bazelbuild/rules_go/blob/master/go/toolchains.rst#pack) action generators provided by [go_context](https://togithub.com/bazelbuild/rules_go/blob/master/go/toolchains.rst#go_context) are deprecated and planned for removal in version v0.36.0. Please leave a comment on the [tracking bug](https://togithub.com/bazelbuild/rules_go/issues/3168) if [archive](https://togithub.com/bazelbuild/rules_go/blob/master/go/toolchains.rst#archive) and [link](https://togithub.com/bazelbuild/rules_go/blob/master/go/toolchains.rst#link) are not suitable replacements for your use cases. #### Bug Fixes - [@​sluongng](https://togithub.com/sluongng) fixed a race condition that could cause non-sandboxed builds of `go_test` targets to fail ([https://github.com/bazelbuild/rules_go/pull/3145](https://togithub.com/bazelbuild/rules_go/pull/3145)) - [@​abhinav](https://togithub.com/abhinav) made `//go:embed` work with `go_path` ([https://github.com/bazelbuild/rules_go/pull/3163](https://togithub.com/bazelbuild/rules_go/pull/3163)) - [@​xytan0056](https://togithub.com/xytan0056) made gopackagesdriver work with Go 1.18 ([https://github.com/bazelbuild/rules_go/pull/3157](https://togithub.com/bazelbuild/rules_go/pull/3157)) - [@​nickgooding](https://togithub.com/nickgooding) ensured that `gomock` can be used with any Gazelle naming convention ([https://github.com/bazelbuild/rules_go/pull/3155](https://togithub.com/bazelbuild/rules_go/pull/3155)) - `go_library` targets using CGo can now reference unresolved symbols ([https://github.com/bazelbuild/rules_go/pull/3174](https://togithub.com/bazelbuild/rules_go/pull/3174)) Thanks to all of the contributors! #### Compatibility The minimum required version of Bazel remains at 4.2.1. #### Updated dependencies - Updated `org_golang_x_sys`, `org_golang_x_xerrors`, `org_golang_google_genproto`, `go_googleapis` to their most recent commit as of 2022-06-05 As always, you can use higher versions of rules_go's dependencies by declaring them in WORKSPACE before calling go_rules_dependencies. Lower versions may work but are not supported. #### `WORKSPACE` code load("@​bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "685052b498b6ddfe562ca7a97736741d87916fe536623afb7da2824c0211c369", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.33.0/rules_go-v0.33.0.zip", "https://github.com/bazelbuild/rules_go/releases/download/v0.33.0/rules_go-v0.33.0.zip", ], ) load("@​io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") go_rules_dependencies() go_register_toolchains(version = "1.18.3") </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, click this checkbox. --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/gapic-config-validator).
FWIW, I think using target's name in the action input might be an anti pattern.
In such (rare?) case, the 80 test binary compilation/link might run not once, but 80 times. I am convinced that this is not an issue worth solving right now 🤔 But thinking about the (unrelated) use case of constructing a synthetic tests for RBE, where I want the build graph to be widen to benefit from parallelism, made me think back about this PR and how it might have unintentionally enabled such use case. |
Avoiding this would be harder than expected though: The command line is part of the action key computation and necessarily contains the path of the output of the compile/link actions, which is already derived from the test name. If I'm not missing anything, the recent change thus should make a difference here. |
I quickly created a test like this:
Then I ran the test before and after reverting this commit.
And the result seems to be that I event tried doing this on top of my patch
And then ran the same test: same result, ActionKey hash always changed. So it's safe to conclude that this PR did not introduce a regression. 😇 I was being paranoid for no reason. Sorry for the noise 🙇 |
compilepkg: fix race when run without sandbox
On platforms without sandbox execution support such as Windows, multiple
go_test targets declared in the same package would cause a race condition.
For each of go_test targets, there would be internal archive and
external archive that needs to compile from source files. However, due
to testfilter, external archive would end up without any Go source and
thus compilepkg needs to generate a dummy source file
_empty.go
totrick 'go tool compile'.
This
_empty.go
file is generated in the output path of the Bazelpackage thus multiple go_test targets in the same package would generate
this file using the same path. On a sandbox supported platform,
this is not a problem as the full path is prefixed with the sandbox root
dir. However, without sandbox, the full path is the same for each
go_test's external archive compilation, leading to a race condition
where multiple compilations running in parallel would compete to
create/delete the same file.
Fix this by using the unique importPath to create a directory to store
the _empty.go file. This would effectively give each go_test compilation
it's own _empty.go file in non-sandbox environment.
Worth to note that in current solution, we still have yet to solve
problem when 'importPath' is not provided. For example, in a setup like
this where
go_library
does not exist,importPath
will be blank andthus causes similar issues on non-sandbox platforms.
Although this is a valid use case, we recommend avoid setting up tests
this way. Instead, you could setup a single go_test target with multiple
shards to achieve similar result:
For more information, please review Bazel Test Sharding documentation(1)
(1): https://docs.bazel.build/versions/main/test-encyclopedia.html#test-sharding
Fix #3144