@@ -61,6 +61,11 @@ func (p poolWrapper) Close() error {
61
61
return nil
62
62
}
63
63
64
+ type indexedOID struct {
65
+ Index int
66
+ OID oid.ID
67
+ }
68
+
64
69
// Service is a service that fetches blocks from NeoFS.
65
70
type Service struct {
66
71
// isActive denotes whether the service is working or in the process of shutdown.
@@ -71,15 +76,15 @@ type Service struct {
71
76
operationMode OperationMode
72
77
73
78
stateRootInHeader bool
74
- // headerSize is the size of the header in bytes .
75
- headerSize int
79
+ // headerSizeMap is a map of height to expected header size .
80
+ headerSizeMap map [ int ] int
76
81
77
82
chain Ledger
78
83
pool poolWrapper
79
84
enqueue func (obj any ) error
80
85
account * wallet.Account
81
86
82
- oidsCh chan oid. ID
87
+ oidsCh chan indexedOID
83
88
// wg is a wait group for block downloaders.
84
89
wg sync.WaitGroup
85
90
@@ -97,7 +102,7 @@ type Service struct {
97
102
shutdownCallback func ()
98
103
99
104
// Depends on the OperationMode, the following functions are set to the appropriate functions.
100
- getFunc func (ctx context.Context , oid string ) (io.ReadCloser , error )
105
+ getFunc func (ctx context.Context , oid string , index int ) (io.ReadCloser , error )
101
106
readFunc func (rc io.ReadCloser ) (any , error )
102
107
heightFunc func () uint32
103
108
}
@@ -164,7 +169,7 @@ func New(chain Ledger, cfg config.NeoFSBlockFetcher, logger *zap.Logger, put fun
164
169
log : logger ,
165
170
cfg : cfg ,
166
171
operationMode : opt ,
167
- headerSize : getHeaderSize (chain .GetConfig ()),
172
+ headerSizeMap : getHeaderSizeMap (chain .GetConfig ()),
168
173
169
174
enqueue : put ,
170
175
account : account ,
@@ -180,12 +185,17 @@ func New(chain Ledger, cfg config.NeoFSBlockFetcher, logger *zap.Logger, put fun
180
185
// * first full block of OIDs is processing by Downloader
181
186
// * second full block of OIDs is available to be fetched by Downloader immediately
182
187
// * third half-filled block of OIDs is being collected by OIDsFetcher.
183
- oidsCh : make (chan oid. ID , 2 * cfg .OIDBatchSize ),
188
+ oidsCh : make (chan indexedOID , 2 * cfg .OIDBatchSize ),
184
189
}, nil
185
190
}
186
191
187
- func getHeaderSize (chain config.Blockchain ) int {
188
- return block .GetExpectedHeaderSize (chain .StateRootInHeader , chain .GetNumOfCNs (0 ))
192
+ func getHeaderSizeMap (chain config.Blockchain ) map [int ]int {
193
+ headerSizeMap := make (map [int ]int )
194
+ headerSizeMap [0 ] = block .GetExpectedHeaderSize (chain .StateRootInHeader , chain .GetNumOfCNs (0 ))
195
+ for height := range chain .CommitteeHistory {
196
+ headerSizeMap [int (height )] = block .GetExpectedHeaderSize (chain .StateRootInHeader , chain .GetNumOfCNs (height ))
197
+ }
198
+ return headerSizeMap
189
199
}
190
200
191
201
// Start runs the NeoFS BlockFetcher service.
@@ -276,11 +286,13 @@ func (bfs *Service) oidDownloader() {
276
286
func (bfs * Service ) blockDownloader () {
277
287
defer bfs .wg .Done ()
278
288
279
- for blkOid := range bfs .oidsCh {
289
+ for indexedOid := range bfs .oidsCh {
290
+ index := indexedOid .Index
291
+ blkOid := indexedOid .OID
280
292
ctx , cancel := context .WithTimeout (bfs .ctx , bfs .cfg .Timeout )
281
293
defer cancel ()
282
294
283
- rc , err := bfs .getFunc (ctx , blkOid .String ())
295
+ rc , err := bfs .getFunc (ctx , blkOid .String (), index )
284
296
if err != nil {
285
297
if isContextCanceledErr (err ) {
286
298
return
@@ -346,15 +358,15 @@ func (bfs *Service) fetchOIDsFromIndexFiles() error {
346
358
347
359
blockCtx , blockCancel := context .WithTimeout (bfs .ctx , bfs .cfg .Timeout )
348
360
defer blockCancel ()
349
- oidsRC , err := bfs .objectGet (blockCtx , blockOidsObject [0 ].String ())
361
+ oidsRC , err := bfs .objectGet (blockCtx , blockOidsObject [0 ].String (), - 1 )
350
362
if err != nil {
351
363
if isContextCanceledErr (err ) {
352
364
return nil
353
365
}
354
366
return fmt .Errorf ("failed to fetch '%s' object with index %d: %w" , bfs .cfg .IndexFileAttribute , startIndex , err )
355
367
}
356
368
357
- err = bfs .streamBlockOIDs (oidsRC , int (skip ))
369
+ err = bfs .streamBlockOIDs (oidsRC , int (startIndex ), int ( skip ))
358
370
if err != nil {
359
371
if isContextCanceledErr (err ) {
360
372
return nil
@@ -369,7 +381,7 @@ func (bfs *Service) fetchOIDsFromIndexFiles() error {
369
381
}
370
382
371
383
// streamBlockOIDs reads block OIDs from the read closer and sends them to the OIDs channel.
372
- func (bfs * Service ) streamBlockOIDs (rc io.ReadCloser , skip int ) error {
384
+ func (bfs * Service ) streamBlockOIDs (rc io.ReadCloser , startIndex , skip int ) error {
373
385
defer rc .Close ()
374
386
oidBytes := make ([]byte , oid .Size )
375
387
oidsProcessed := 0
@@ -396,7 +408,7 @@ func (bfs *Service) streamBlockOIDs(rc io.ReadCloser, skip int) error {
396
408
select {
397
409
case <- bfs .exiterToOIDDownloader :
398
410
return nil
399
- case bfs .oidsCh <- oidBlock :
411
+ case bfs .oidsCh <- indexedOID { Index : startIndex * int ( bfs . cfg . IndexFileSize ) + oidsProcessed , OID : oidBlock } :
400
412
}
401
413
402
414
oidsProcessed ++
@@ -441,12 +453,14 @@ func (bfs *Service) fetchOIDsBySearch() error {
441
453
bfs .log .Info (fmt .Sprintf ("NeoFS BlockFetcher service: no block found with index %d, stopping" , startIndex ))
442
454
return nil
443
455
}
456
+ index := int (startIndex )
444
457
for _ , oid := range blockOids {
445
458
select {
446
459
case <- bfs .exiterToOIDDownloader :
447
460
return nil
448
- case bfs .oidsCh <- oid :
461
+ case bfs .oidsCh <- indexedOID { Index : index , OID : oid } :
449
462
}
463
+ index ++ //Won't work properly if neofs.ObjectSearch results are not ordered.
450
464
}
451
465
startIndex += batchSize
452
466
}
@@ -580,7 +594,7 @@ func (bfs *Service) retry(action func() error) error {
580
594
return err
581
595
}
582
596
583
- func (bfs * Service ) objectGet (ctx context.Context , oid string ) (io.ReadCloser , error ) {
597
+ func (bfs * Service ) objectGet (ctx context.Context , oid string , index int ) (io.ReadCloser , error ) {
584
598
u , err := url .Parse (fmt .Sprintf ("%s:%s/%s" , neofs .URIScheme , bfs .cfg .ContainerID , oid ))
585
599
if err != nil {
586
600
return nil , err
@@ -593,8 +607,19 @@ func (bfs *Service) objectGet(ctx context.Context, oid string) (io.ReadCloser, e
593
607
return rc , err
594
608
}
595
609
596
- func (bfs * Service ) objectGetRange (ctx context.Context , oid string ) (io.ReadCloser , error ) {
597
- u , err := url .Parse (fmt .Sprintf ("%s:%s/%s/%s/%d|%d" , neofs .URIScheme , bfs .cfg .ContainerID , oid , "range" , 0 , bfs .headerSize ))
610
+ func (bfs * Service ) objectGetRange (ctx context.Context , oid string , height int ) (io.ReadCloser , error ) {
611
+ nearestHeight := 0
612
+ for h := range bfs .headerSizeMap {
613
+ if h <= height && h > nearestHeight {
614
+ nearestHeight = h
615
+ }
616
+ if nearestHeight >= height {
617
+ break
618
+ }
619
+ }
620
+
621
+ size := bfs .headerSizeMap [nearestHeight ]
622
+ u , err := url .Parse (fmt .Sprintf ("%s:%s/%s/%s/%d|%d" , neofs .URIScheme , bfs .cfg .ContainerID , oid , "range" , 0 , size ))
598
623
if err != nil {
599
624
return nil , err
600
625
}
0 commit comments