Skip to content

Commit 830ba89

Browse files
javierhonducokakkoyun
authored andcommitted
debuginfo: Fix race when extracting debug info files (#444)
1 parent b378519 commit 830ba89

File tree

1 file changed

+42
-3
lines changed

1 file changed

+42
-3
lines changed

pkg/debuginfo/debuginfo.go

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ type DebugInfo struct {
3838
existsCache cache.Cache
3939
debugInfoFileCache cache.Cache
4040

41+
uploadingCache cache.Cache
42+
4143
*Extractor
4244
*Uploader
4345
*Finder
@@ -53,12 +55,43 @@ func New(logger log.Logger, client Client, tmp string) *DebugInfo {
5355
),
5456
debugInfoFileCache: cache.New(cache.WithMaximumSize(128)), // Arbitrary cache size.
5557
client: client,
56-
Extractor: NewExtractor(logger, client, tmp),
57-
Uploader: NewUploader(logger, client),
58-
Finder: NewFinder(logger),
58+
// Up to this amount of debug files in flight at once. This number is very large
59+
// and unlikely to happen in real life.
60+
uploadingCache: cache.New(
61+
cache.WithMaximumSize(1024),
62+
),
63+
Extractor: NewExtractor(logger, client, tmp),
64+
Uploader: NewUploader(logger, client),
65+
Finder: NewFinder(logger),
5966
}
6067
}
6168

69+
// We upload the debug information files concurrently. In case
70+
// of two files with the same buildID are extracted at the same
71+
// time, they will be written to the same file.
72+
//
73+
// Most of the time, the file is, erm, eventually consistent-ish,
74+
// and once all the writers are done, the debug file looks is an ELF
75+
// with the correct bytes.
76+
//
77+
// However I don't believe there's any guarantees on this, so the
78+
// files aren't getting corrupted most of the time by sheer luck.
79+
//
80+
// These two helpers make sure that we don't try to extract + upload
81+
// the same buildID concurrently.
82+
func (di *DebugInfo) alreadyUploading(buildID string) bool {
83+
_, ok := di.uploadingCache.GetIfPresent(buildID)
84+
return ok
85+
}
86+
87+
func (di *DebugInfo) markAsUploading(buildID string) {
88+
di.uploadingCache.Put(buildID, true)
89+
}
90+
91+
func (di *DebugInfo) removeAsUploading(buildID string) {
92+
di.uploadingCache.Invalidate(buildID)
93+
}
94+
6295
// EnsureUploaded ensures that the extracted or the found debuginfo for the given buildID is uploaded.
6396
func (di *DebugInfo) EnsureUploaded(ctx context.Context, objFiles []*objectfile.MappedObjectFile) {
6497
type cleanup struct {
@@ -75,6 +108,11 @@ func (di *DebugInfo) EnsureUploaded(ctx context.Context, objFiles []*objectfile.
75108
continue
76109
}
77110

111+
if di.alreadyUploading(buildID) {
112+
continue
113+
}
114+
di.markAsUploading(buildID)
115+
78116
// Finds the debuginfo file. Interim files can be clean up.
79117
dbgInfoPath, shouldCleanup := di.debugInfoFilePath(ctx, buildID, objFile)
80118
// Cleanup the extracted debug information file.
@@ -98,6 +136,7 @@ func (di *DebugInfo) EnsureUploaded(ctx context.Context, objFiles []*objectfile.
98136
level.Error(logger).Log("msg", "failed to upload debug information", "err", err)
99137
continue
100138
}
139+
di.removeAsUploading(buildID)
101140
level.Debug(logger).Log("msg", "debug information uploaded successfully")
102141
}
103142

0 commit comments

Comments
 (0)