@@ -6,13 +6,15 @@ import (
6
6
"errors"
7
7
"fmt"
8
8
"github.com/inconshreveable/log15"
9
+ "github.com/panjf2000/ants/v2"
9
10
"io/ioutil"
10
11
"math/big"
11
12
"net/http"
12
13
"net/url"
13
14
"path"
14
15
"strconv"
15
16
"strings"
17
+ "sync"
16
18
"time"
17
19
18
20
"github.com/everFinance/goar/types"
@@ -503,6 +505,109 @@ func (c *Client) DownloadChunkData(id string) ([]byte, error) {
503
505
return data , nil
504
506
}
505
507
508
+ func (c * Client ) ConcurrentDownloadChunkData (id string , concurrentNum int ) ([]byte , error ) {
509
+ offsetResponse , err := c .getTransactionOffset (id )
510
+ if err != nil {
511
+ return nil , err
512
+ }
513
+ size , err := strconv .ParseInt (offsetResponse .Size , 10 , 64 )
514
+ if err != nil {
515
+ return nil , err
516
+ }
517
+ endOffset , err := strconv .ParseInt (offsetResponse .Offset , 10 , 64 )
518
+ if err != nil {
519
+ return nil , err
520
+ }
521
+ startOffset := endOffset - size + 1
522
+
523
+ offsetArr := make ([]int64 , 0 , 5 )
524
+ for i := 0 ; int64 (i )+ startOffset < endOffset ; {
525
+ offsetArr = append (offsetArr , int64 (i )+ startOffset )
526
+ i += types .MAX_CHUNK_SIZE
527
+ }
528
+
529
+ if len (offsetArr ) <= 3 { // not need concurrent get chunks
530
+ return c .DownloadChunkData (id )
531
+ }
532
+
533
+ log .Debug ("need download chunks length" , "length" , len (offsetArr ))
534
+ // concurrent get chunks
535
+ type OffsetSort struct {
536
+ Idx int
537
+ Offset int64
538
+ }
539
+
540
+ chunkArr := make ([][]byte , len (offsetArr )- 2 )
541
+ var (
542
+ lock sync.Mutex
543
+ wg sync.WaitGroup
544
+ )
545
+ if concurrentNum <= 0 {
546
+ concurrentNum = types .DEFAULT_CHUNK_CONCURRENT_NUM
547
+ }
548
+ p , _ := ants .NewPoolWithFunc (concurrentNum , func (i interface {}) {
549
+ defer wg .Done ()
550
+ oss := i .(OffsetSort )
551
+ chunkData , err := c .getChunkData (oss .Offset )
552
+ if err != nil {
553
+ count := 0
554
+ for count < 50 {
555
+ time .Sleep (2 * time .Second )
556
+ chunkData , err = c .getChunkData (oss .Offset )
557
+ if err == nil {
558
+ break
559
+ }
560
+ log .Error ("retry getChunkData failed and try again..." , "err" , err , "offset" , oss .Offset , "retryCount" , count )
561
+ count ++
562
+ }
563
+ }
564
+ lock .Lock ()
565
+ chunkArr [oss .Idx ] = chunkData
566
+ lock .Unlock ()
567
+ })
568
+
569
+ defer p .Release ()
570
+
571
+ for i , offset := range offsetArr [:len (offsetArr )- 2 ] {
572
+ wg .Add (1 )
573
+ if err := p .Invoke (OffsetSort {Idx : i , Offset : offset }); err != nil {
574
+ log .Error ("p.Invoke(i)" , "err" , err , "i" , i )
575
+ return nil , err
576
+ }
577
+ }
578
+ wg .Wait ()
579
+
580
+ // add latest 2 chunks
581
+ start := offsetArr [len (offsetArr )- 3 ] + types .MAX_CHUNK_SIZE
582
+ for i := 0 ; int64 (i )+ start < endOffset ; {
583
+ chunkData , err := c .getChunkData (int64 (i ) + start )
584
+ if err != nil {
585
+ count := 0
586
+ for count < 50 {
587
+ time .Sleep (2 * time .Second )
588
+ chunkData , err = c .getChunkData (int64 (i ) + start )
589
+ if err == nil {
590
+ break
591
+ }
592
+ log .Error ("retry getChunkData failed and try again..." , "err" , err , "offset" , int64 (i )+ start , "retryCount" , count )
593
+ count ++
594
+ }
595
+ }
596
+ chunkArr = append (chunkArr , chunkData )
597
+ i += len (chunkData )
598
+ }
599
+
600
+ // assemble data
601
+ data := make ([]byte , 0 , size )
602
+ for _ , chunk := range chunkArr {
603
+ if chunk == nil {
604
+ return nil , errors .New ("concurrent get chunk failed" )
605
+ }
606
+ data = append (data , chunk ... )
607
+ }
608
+ return data , nil
609
+ }
610
+
506
611
func (c * Client ) GetUnconfirmedTx (arId string ) (* types.Transaction , error ) {
507
612
_path := fmt .Sprintf ("unconfirmed_tx/%s" , arId )
508
613
body , statusCode , err := c .httpGet (_path )
0 commit comments