@@ -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.
6396func (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