pre-populate archiveDownloadCancel to correctly capture downloadComplete and avoid potential race condition

This commit is contained in:
Marcin Czenko 2025-10-27 20:46:39 +01:00
parent 5b88275fc7
commit 5b99a900d5
No known key found for this signature in database
GPG Key ID: A0449219BDBA98AE

View File

@ -147,6 +147,10 @@ func (d *CodexArchiveDownloader) downloadAllArchives() {
var archivesList []archiveInfo
for hash, metadata := range d.index.Archives {
// Skip archives we already have
if slices.Contains(d.existingArchiveIDs, hash) {
continue
}
archivesList = append(archivesList, archiveInfo{
hash: hash,
from: metadata.Metadata.From,
@ -166,6 +170,17 @@ func (d *CodexArchiveDownloader) downloadAllArchives() {
return 0 // equal timestamps
})
// Pre-populate archiveDownloadCancel with all archives that need downloading
// This ensures len(archiveDownloadCancel) correctly represents total pending work
// and prevents race condition where fast-completing goroutines set downloadComplete=true
// before all archives are added to the map
d.mu.Lock()
for _, archive := range archivesList {
d.archiveDownloadCancel[archive.hash] = make(chan struct{})
d.archiveDownloadProgress[archive.hash] = 0
}
d.mu.Unlock()
// Monitor for cancellation in a separate goroutine
go func() {
ticker := time.NewTicker(100 * time.Millisecond)
@ -202,18 +217,10 @@ func (d *CodexArchiveDownloader) downloadAllArchives() {
// Download each missing archive
for _, archive := range archivesList {
// Check if we already have this archive
hasArchive := slices.Contains(d.existingArchiveIDs, archive.hash)
if hasArchive {
continue
}
archiveCancelChan := make(chan struct{})
d.mu.Lock()
d.archiveDownloadProgress[archive.hash] = 0
d.archiveDownloadCancel[archive.hash] = archiveCancelChan
d.mu.Unlock()
// Get the pre-created cancel channel for this archive
d.mu.RLock()
archiveCancelChan := d.archiveDownloadCancel[archive.hash]
d.mu.RUnlock()
// Call callback before starting
if d.onStartingArchiveDownload != nil {