Description of the problem / feature request / question:
Our org has about 50 engineers using Bazel, with a remote cache but without remote build. About once every 3-4 weeks, I would hear of a case of someone's build that was failing in strange ways when the remote cache was turned on, but would succeed when the cache was off.
I finally got a repro case, and was able to figure out what was happening. Bazel's remote spawn strategy does its work in this order:
- Compute the hash of the action (which includes the hash of all the input files)
- Check if the remote cache contains the action result matching that hash
- If it does, then download it
- If it doesn't, then do a local build and upload the action result
But if the user makes any changes to the sources (e.g. saves a file, or uses git to check out a different branch of their code) after step 1, but before the build in step 3, then you will end up with an incorrect (corrupt) entry in the cache: Its hash matches the input files when step 1 executed, but its contents do not match what would have been built from those input files — its contents match what was built from the modified input files.
From that point on, all other developers on the team who try to build that same code will download the incorrect build results.
Interestingly, I think this cannot cause cache problems if you are using remote cache WITH remote build. In that scenario, Bazel's SimpleBlobStoreActionCache.uploadFileContents() will first read the file into memory, then compute its hash, and upload the already in-memory blob. So the file contents in the cache are guaranteed to be accurate (the source file's hash matches the source file's contents). I haven't tried it, but I imagine that the worst that could happen — and I'm not even sure if this could happen — is that the remote build might fail because it can't find the input files it wants. No serious harm done.
If possible, provide a minimal example to reproduce the problem:
This BUILD file has a rule called :race which, when built, will first sleep for a few seconds, and then will simply cat foo.in to foo.out:
genrule(
name = "race",
srcs = ["foo.in"],
outs = ["foo.out"],
cmd = "sleep 10; cat $(SRCS) > $@"
)
Make a file foo.in: echo 1 > foo.in
Start a build with a command line similar to this one (for this test, I have nginx running on localhost acting as a remote cache; you will need to set up some sort of similar remote cache):
bazel --host_jvm_args=-Dbazel.DigestFunction=SHA1 build --spawn_strategy=remote --remote_rest_cache=http://localhost:8000/bazel-cache/race :race
While the build is happening — during the sleep 10 — in another shell, change the contents of foo.in: echo 2 > foo.in
The build will complete, and bazel-genfiles/foo.out will, not surprisingly, contain 2. That's not a bug. But then:
- Do a clean:
bazel --host_jvm_args=-Dbazel.DigestFunction=SHA1 clean
- Reset
foo.in to its old contents: echo 1 > foo.in
- Do another
bazel build, with the same command line as above.
At this point, bazel-genfiles/foo.out will contain 2, because that's what Bazel found in the remote cache. This is definitely wrong.
Environment info
OSX; probably on Linux too, I haven't tested it
- Bazel version (output of
bazel info release):
0.5.2
Description of the problem / feature request / question:
Our org has about 50 engineers using Bazel, with a remote cache but without remote build. About once every 3-4 weeks, I would hear of a case of someone's build that was failing in strange ways when the remote cache was turned on, but would succeed when the cache was off.
I finally got a repro case, and was able to figure out what was happening. Bazel's remote spawn strategy does its work in this order:
But if the user makes any changes to the sources (e.g. saves a file, or uses git to check out a different branch of their code) after step 1, but before the build in step 3, then you will end up with an incorrect (corrupt) entry in the cache: Its hash matches the input files when step 1 executed, but its contents do not match what would have been built from those input files — its contents match what was built from the modified input files.
From that point on, all other developers on the team who try to build that same code will download the incorrect build results.
Interestingly, I think this cannot cause cache problems if you are using remote cache WITH remote build. In that scenario, Bazel's
SimpleBlobStoreActionCache.uploadFileContents()will first read the file into memory, then compute its hash, and upload the already in-memory blob. So the file contents in the cache are guaranteed to be accurate (the source file's hash matches the source file's contents). I haven't tried it, but I imagine that the worst that could happen — and I'm not even sure if this could happen — is that the remote build might fail because it can't find the input files it wants. No serious harm done.If possible, provide a minimal example to reproduce the problem:
This
BUILDfile has a rule called:racewhich, when built, will first sleep for a few seconds, and then will simply catfoo.intofoo.out:Make a file
foo.in:echo 1 > foo.inStart a build with a command line similar to this one (for this test, I have nginx running on localhost acting as a remote cache; you will need to set up some sort of similar remote cache):
While the build is happening — during the
sleep 10— in another shell, change the contents offoo.in:echo 2 > foo.inThe build will complete, and
bazel-genfiles/foo.outwill, not surprisingly, contain2. That's not a bug. But then:bazel --host_jvm_args=-Dbazel.DigestFunction=SHA1 cleanfoo.into its old contents:echo 1 > foo.inbazel build, with the same command line as above.At this point,
bazel-genfiles/foo.outwill contain2, because that's what Bazel found in the remote cache. This is definitely wrong.Environment info
OSX; probably on Linux too, I haven't tested it
bazel info release):0.5.2