diff --git a/erigon-lib/downloader/downloader.go b/erigon-lib/downloader/downloader.go index 33cb15da28a..2a438cc2432 100644 --- a/erigon-lib/downloader/downloader.go +++ b/erigon-lib/downloader/downloader.go @@ -582,7 +582,7 @@ func (d *Downloader) AddNewSeedableFile(ctx context.Context, name string) error if err != nil { return fmt.Errorf("AddNewSeedableFile: %w", err) } - err = addTorrentFile(ctx, ts, d.torrentClient, d.webseeds) + _, _, err = addTorrentFile(ctx, ts, d.torrentClient, d.webseeds) if err != nil { return fmt.Errorf("addTorrentFile: %w", err) } @@ -619,11 +619,13 @@ func (d *Downloader) AddMagnetLink(ctx context.Context, infoHash metainfo.Hash, if err != nil { return err } - spec.DisallowDataDownload = true - t, _, err := d.torrentClient.AddTorrentSpec(spec) + t, ok, err := addTorrentFile(ctx, spec, d.torrentClient, d.webseeds) if err != nil { return err } + if !ok { + return nil + } d.wg.Add(1) go func(t *torrent.Torrent) { defer d.wg.Done() @@ -672,7 +674,7 @@ func (d *Downloader) addTorrentFilesFromDisk(quiet bool) error { return err } for i, ts := range files { - err := addTorrentFile(d.ctx, ts, d.torrentClient, d.webseeds) + _, _, err := addTorrentFile(d.ctx, ts, d.torrentClient, d.webseeds) if err != nil { return err } diff --git a/erigon-lib/downloader/util.go b/erigon-lib/downloader/util.go index 053e830c851..4b2d3d3470f 100644 --- a/erigon-lib/downloader/util.go +++ b/erigon-lib/downloader/util.go @@ -306,29 +306,56 @@ func loadTorrent(torrentFilePath string) (*torrent.TorrentSpec, error) { // added first time - pieces verification process will start (disk IO heavy) - Progress // kept in `piece completion storage` (surviving reboot). Once it done - no disk IO needed again. // Don't need call torrent.VerifyData manually -func addTorrentFile(ctx context.Context, ts *torrent.TorrentSpec, torrentClient *torrent.Client, webseeds *WebSeeds) error { +func addTorrentFile(ctx context.Context, ts *torrent.TorrentSpec, torrentClient *torrent.Client, webseeds *WebSeeds) (t *torrent.Torrent, ok bool, err error) { + ts.ChunkSize = downloadercfg.DefaultNetworkChunkSize + ts.DisallowDataDownload = true + ts.DisableInitialPieceCheck = true + //re-try on panic, with 0 ChunkSize (lib doesn't allow change this field for existing torrents) + defer func() { + rec := recover() + if rec != nil { + ts.ChunkSize = 0 + t, ok, err = _addTorrentFile(ctx, ts, torrentClient, webseeds) + } + }() + + t, ok, err = _addTorrentFile(ctx, ts, torrentClient, webseeds) + if err != nil { + ts.ChunkSize = 0 + return _addTorrentFile(ctx, ts, torrentClient, webseeds) + } + return t, ok, err +} + +func _addTorrentFile(ctx context.Context, ts *torrent.TorrentSpec, torrentClient *torrent.Client, webseeds *WebSeeds) (t *torrent.Torrent, ok bool, err error) { select { case <-ctx.Done(): - return ctx.Err() + return nil, false, ctx.Err() default: } - wsUrls, ok := webseeds.ByFileName(ts.DisplayName) - if ok { - ts.Webseeds = append(ts.Webseeds, wsUrls...) - } - _, ok = torrentClient.Torrent(ts.InfoHash) - if !ok { // can set ChunkSize only for new torrents - ts.ChunkSize = downloadercfg.DefaultNetworkChunkSize - } else { - ts.ChunkSize = 0 + ts.Webseeds, _ = webseeds.ByFileName(ts.DisplayName) + var have bool + t, have = torrentClient.Torrent(ts.InfoHash) + if !have { + t, _, err := torrentClient.AddTorrentSpec(ts) + if err != nil { + return nil, false, fmt.Errorf("addTorrentFile %s: %w", ts.DisplayName, err) + } + return t, true, nil } - ts.DisallowDataDownload = true - _, _, err := torrentClient.AddTorrentSpec(ts) - if err != nil { - return fmt.Errorf("addTorrentFile %s: %w", ts.DisplayName, err) + + select { + case <-t.GotInfo(): + t.AddWebSeeds(ts.Webseeds) + default: + t, _, err = torrentClient.AddTorrentSpec(ts) + if err != nil { + return nil, false, fmt.Errorf("addTorrentFile %s: %w", ts.DisplayName, err) + } } - return nil + + return t, true, nil } func savePeerID(db kv.RwDB, peerID torrent.PeerID) error {