Skip to content

Commit 9a70805

Browse files
michaeledgarcopybara-github
authored andcommitted
Fix double shutdown of BuildEventArtifactUploader when BES+File output enabled.
When both BES uploading and File BEP output are enabled, a single BuildEventArtifactUploader object is shared by two different BuildEventTransports. Both were calling #shutdown() which in turn called ByteStreamUploader#shutdown(). If shutdown is called while one transport is still uploading, the ByteStreamUploader will fail an assertion and crash. This change adds reference counting to the BuildEventArtifactUploader interface and ensures the reference counts are maintained correctly when sharing a BuildEventArtifactUploader across multiple independent BuildEventTransport threads. Fixes #12575. RELNOTES: None. TESTED=Made repro modifications to GrpcCacheClient.java described in #12575 and confirmed crash without this change. Implemented this fix, observed crash was no longer reproducible. Added logs to ByteStreamBuildEventArtifactUploader#deallocate() to verify deallocation happened after both BuildEventTransports had completed. PiperOrigin-RevId: 349589743
1 parent c833660 commit 9a70805

13 files changed

Lines changed: 90 additions & 46 deletions

File tree

src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceModule.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,8 @@ private static class ThrowingBuildEventArtifactUploaderSupplier {
853853
}
854854

855855
BuildEventArtifactUploader get() throws IOException {
856-
if (memoizedValue == null && exception == null) {
856+
boolean needsInitialization = memoizedValue == null;
857+
if (needsInitialization && exception == null) {
857858
try {
858859
memoizedValue = callable.call();
859860
} catch (IOException e) {
@@ -864,6 +865,9 @@ BuildEventArtifactUploader get() throws IOException {
864865
}
865866
}
866867
if (memoizedValue != null) {
868+
if (!needsInitialization) {
869+
memoizedValue.retain();
870+
}
867871
return memoizedValue;
868872
}
869873
throw exception;

src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceUploader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ public void run() {
355355
logger.atSevere().log("BES upload failed due to a RuntimeException / Error. This is a bug.");
356356
throw e;
357357
} finally {
358-
buildEventUploader.shutdown();
358+
buildEventUploader.release();
359359
MoreExecutors.shutdownAndAwaitTermination(timeoutExecutor, 0, TimeUnit.MILLISECONDS);
360360
closeFuture.set(null);
361361
}

src/main/java/com/google/devtools/build/lib/buildeventstream/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ java_library(
2929
"//third_party:flogger",
3030
"//third_party:guava",
3131
"//third_party:jsr305",
32+
"//third_party:netty",
3233
"//third_party/protobuf:protobuf_java",
3334
],
3435
)

src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventArtifactUploader.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.devtools.build.lib.buildeventstream.BuildEvent.LocalFile;
2121
import com.google.devtools.build.lib.buildeventstream.BuildEvent.LocalFile.LocalFileType;
2222
import com.google.devtools.build.lib.vfs.Path;
23+
import io.netty.util.ReferenceCounted;
2324
import java.io.IOException;
2425
import java.io.InputStream;
2526
import java.io.OutputStream;
@@ -30,7 +31,7 @@
3031
import javax.annotation.Nullable;
3132

3233
/** Uploads artifacts referenced by the Build Event Protocol (BEP). */
33-
public interface BuildEventArtifactUploader {
34+
public interface BuildEventArtifactUploader extends ReferenceCounted {
3435
/**
3536
* Asynchronously uploads a set of files referenced by the protobuf representation of a {@link
3637
* BuildEvent}. This method is expected to return quickly.
@@ -78,11 +79,6 @@ public ListenableFuture<String> uriFuture() {
7879
}
7980
};
8081

81-
/**
82-
* Shutdown any resources associated with the uploader.
83-
*/
84-
void shutdown();
85-
8682
/**
8783
* Return true if the upload may be "slow". Examples of slowness include writes to remote storage.
8884
*/

src/main/java/com/google/devtools/build/lib/buildeventstream/LocalFilesArtifactUploader.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@
1818
import com.google.devtools.build.lib.buildeventstream.BuildEvent.LocalFile;
1919
import com.google.devtools.build.lib.buildeventstream.PathConverter.FileUriPathConverter;
2020
import com.google.devtools.build.lib.vfs.Path;
21+
import io.netty.util.AbstractReferenceCounted;
22+
import io.netty.util.ReferenceCounted;
2123
import java.util.Map;
2224
import java.util.Set;
2325
import java.util.concurrent.ConcurrentHashMap;
2426
import javax.annotation.Nullable;
2527

2628
/** An uploader that simply turns paths into local file URIs. */
27-
public class LocalFilesArtifactUploader implements BuildEventArtifactUploader {
29+
public class LocalFilesArtifactUploader extends AbstractReferenceCounted
30+
implements BuildEventArtifactUploader {
2831
private static final FileUriPathConverter FILE_URI_PATH_CONVERTER = new FileUriPathConverter();
2932
private final ConcurrentHashMap<Path, Boolean> fileIsDirectory = new ConcurrentHashMap<>();
3033

@@ -34,10 +37,15 @@ public ListenableFuture<PathConverter> upload(Map<Path, LocalFile> files) {
3437
}
3538

3639
@Override
37-
public void shutdown() {
40+
protected void deallocate() {
3841
// Intentionally left empty
3942
}
4043

44+
@Override
45+
public ReferenceCounted touch(Object o) {
46+
return this;
47+
}
48+
4149
@Override
4250
public boolean mayBeSlow() {
4351
return false;

src/main/java/com/google/devtools/build/lib/buildeventstream/transports/FileTransport.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ public void run() {
156156
} catch (IOException e) {
157157
logger.atSevere().withCause(e).log("Failed to close BEP file output stream.");
158158
} finally {
159-
uploader.shutdown();
159+
uploader.release();
160160
timeoutExecutor.shutdown();
161161
}
162162
closeFuture.set(null);

src/main/java/com/google/devtools/build/lib/remote/ByteStreamBuildEventArtifactUploader.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
import com.google.devtools.build.lib.remote.util.DigestUtil;
3333
import com.google.devtools.build.lib.vfs.Path;
3434
import io.grpc.Context;
35+
import io.netty.util.AbstractReferenceCounted;
36+
import io.netty.util.ReferenceCounted;
3537
import java.io.IOException;
3638
import java.util.ArrayList;
3739
import java.util.HashMap;
@@ -43,10 +45,9 @@
4345
import java.util.concurrent.atomic.AtomicBoolean;
4446
import javax.annotation.Nullable;
4547

46-
/**
47-
* A {@link BuildEventArtifactUploader} backed by {@link ByteStreamUploader}.
48-
*/
49-
class ByteStreamBuildEventArtifactUploader implements BuildEventArtifactUploader {
48+
/** A {@link BuildEventArtifactUploader} backed by {@link ByteStreamUploader}. */
49+
class ByteStreamBuildEventArtifactUploader extends AbstractReferenceCounted
50+
implements BuildEventArtifactUploader {
5051

5152
private final ListeningExecutorService uploadExecutor;
5253
private final Context ctx;
@@ -243,14 +244,19 @@ public boolean mayBeSlow() {
243244
}
244245

245246
@Override
246-
public void shutdown() {
247+
protected void deallocate() {
247248
if (shutdown.getAndSet(true)) {
248249
return;
249250
}
250251
uploader.release();
251252
uploadExecutor.shutdown();
252253
}
253254

255+
@Override
256+
public ReferenceCounted touch(Object o) {
257+
return this;
258+
}
259+
254260
private static class PathConverterImpl implements PathConverter {
255261

256262
private final String remoteServerInstanceName;

src/main/java/com/google/devtools/build/lib/runtime/BuildEventArtifactUploaderFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public interface BuildEventArtifactUploaderFactory {
2626

2727
/**
2828
* Returns a new instance of a {@link BuildEventArtifactUploader}. The call is responsible for
29-
* calling {@link BuildEventArtifactUploader#shutdown()} on the returned instance.
29+
* calling {@link BuildEventArtifactUploader#release()} on the returned instance.
3030
*/
3131
BuildEventArtifactUploader create(CommandEnvironment env)
3232
throws InvalidPackagePathSymlinkException;

src/test/java/com/google/devtools/build/lib/buildeventstream/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ java_test(
3030
"//src/main/java/com/google/devtools/build/lib/vfs/inmemoryfs",
3131
"//third_party:guava",
3232
"//third_party:junit4",
33+
"//third_party:netty",
3334
"//third_party:truth",
3435
],
3536
)

src/test/java/com/google/devtools/build/lib/buildeventstream/BuildEventArtifactUploaderFactoryMapTest.java

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.google.devtools.build.lib.runtime.BuildEventArtifactUploaderFactoryMap;
2323
import com.google.devtools.build.lib.runtime.CommandEnvironment;
2424
import com.google.devtools.build.lib.vfs.Path;
25+
import io.netty.util.ReferenceCounted;
2526
import java.io.IOException;
2627
import java.util.Map;
2728
import org.junit.Before;
@@ -51,8 +52,38 @@ public boolean mayBeSlow() {
5152
}
5253

5354
@Override
54-
public void shutdown() {
55-
// Intentionally left empty.
55+
public int refCnt() {
56+
return 0;
57+
}
58+
59+
@Override
60+
public ReferenceCounted retain() {
61+
return this;
62+
}
63+
64+
@Override
65+
public ReferenceCounted retain(int i) {
66+
return this;
67+
}
68+
69+
@Override
70+
public ReferenceCounted touch() {
71+
return this;
72+
}
73+
74+
@Override
75+
public ReferenceCounted touch(Object o) {
76+
return this;
77+
}
78+
79+
@Override
80+
public boolean release() {
81+
return false;
82+
}
83+
84+
@Override
85+
public boolean release(int i) {
86+
return false;
5687
}
5788
};
5889
uploaderFactories =

0 commit comments

Comments
 (0)