66using Nethermind . Init . Steps ;
77using Nethermind . Logging ;
88using System . IO . Compression ;
9+ using System . Net ;
910using System . Security . Cryptography ;
10- using Nethermind . Core ;
1111using Nethermind . Core . Extensions ;
1212
1313namespace Nethermind . Init . Snapshot ;
@@ -58,15 +58,21 @@ private async Task InitDbFromSnapshot(CancellationToken cancellationToken)
5858 string snapshotFileName = Path . Combine ( snapshotConfig . SnapshotDirectory , snapshotConfig . SnapshotFileName ) ;
5959 Directory . CreateDirectory ( snapshotConfig . SnapshotDirectory ) ;
6060
61- await DownloadSnapshotTo ( snapshotUrl , snapshotFileName , cancellationToken ) ;
62- // schedule the snapshot file deletion, but only if the download completed
63- // otherwise leave it to resume the download later
64- using Reactive . AnonymousDisposable deleteSnapshot = new ( ( ) =>
61+ while ( true )
6562 {
66- if ( _logger . IsInfo )
67- _logger . Info ( $ "Deleting snapshot file { snapshotFileName } .") ;
68- File . Delete ( snapshotFileName ) ;
69- } ) ;
63+ try
64+ {
65+ await DownloadSnapshotTo ( snapshotUrl , snapshotFileName , cancellationToken ) ;
66+ break ;
67+ }
68+ catch ( IOException e )
69+ {
70+ if ( _logger . IsError )
71+ _logger . Error ( $ "Snapshot download failed. Retrying in 5 seconds. Error: { e } ") ;
72+ await Task . Delay ( TimeSpan . FromSeconds ( 5 ) , cancellationToken ) ;
73+ }
74+ cancellationToken . ThrowIfCancellationRequested ( ) ;
75+ }
7076
7177 if ( snapshotConfig . Checksum is not null )
7278 {
@@ -88,7 +94,12 @@ private async Task InitDbFromSnapshot(CancellationToken cancellationToken)
8894 await ExtractSnapshotTo ( snapshotFileName , dbPath , cancellationToken ) ;
8995
9096 if ( _logger . IsInfo )
97+ {
9198 _logger . Info ( "Database successfully initialized from snapshot." ) ;
99+ _logger . Info ( $ "Deleting snapshot file { snapshotFileName } .") ;
100+ }
101+
102+ File . Delete ( snapshotFileName ) ;
92103 }
93104
94105 private async Task DownloadSnapshotTo (
@@ -116,9 +127,24 @@ private async Task DownloadSnapshotTo(
116127 ( await httpClient . SendAsync ( request , HttpCompletionOption . ResponseHeadersRead , cancellationToken ) )
117128 . EnsureSuccessStatusCode ( ) ;
118129
130+ FileMode snapshotFileMode = FileMode . Create ;
131+ if ( snapshotFileInfo . Exists && response . StatusCode == HttpStatusCode . PartialContent )
132+ {
133+ snapshotFileMode = FileMode . Append ;
134+ }
135+ else if ( response . StatusCode == HttpStatusCode . OK )
136+ {
137+ if ( snapshotFileInfo . Exists && _logger . IsWarn )
138+ _logger . Warn ( "Download couldn't be resumed. Starting from the beginning." ) ;
139+ }
140+ else
141+ {
142+ throw new IOException ( $ "Unexpected status code: { response . StatusCode } ") ;
143+ }
144+
119145 await using Stream contentStream = await response . Content . ReadAsStreamAsync ( cancellationToken ) ;
120146 await using FileStream snapshotFileStream = new (
121- snapshotFileName , FileMode . Append , FileAccess . Write , FileShare . None , BufferSize , true ) ;
147+ snapshotFileName , snapshotFileMode , FileAccess . Write , FileShare . None , BufferSize , true ) ;
122148
123149 long totalBytesRead = snapshotFileStream . Length ;
124150 long ? totalBytesToRead = totalBytesRead + response . Content . Headers . ContentLength ;
0 commit comments