github.com/iotexproject/iotex-core@v1.14.1-rc1/blockindex/sync_indexers.go (about) 1 // Copyright (c) 2023 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package blockindex 7 8 import ( 9 "context" 10 11 "github.com/iotexproject/iotex-core/blockchain/block" 12 "github.com/iotexproject/iotex-core/blockchain/blockdao" 13 ) 14 15 // SyncIndexers is a special index that includes multiple indexes, 16 // which stay in sync when blocks are added. 17 type SyncIndexers struct { 18 indexers []blockdao.BlockIndexer 19 startHeights []uint64 // start height of each indexer, which will be determined when the indexer is started 20 minStartHeight uint64 // minimum start height of all indexers 21 } 22 23 // NewSyncIndexers creates a new SyncIndexers 24 // each indexer will PutBlock one by one in the order of the indexers 25 func NewSyncIndexers(indexers ...blockdao.BlockIndexer) *SyncIndexers { 26 return &SyncIndexers{indexers: indexers} 27 } 28 29 // Start starts the indexer group 30 func (ig *SyncIndexers) Start(ctx context.Context) error { 31 for _, indexer := range ig.indexers { 32 if err := indexer.Start(ctx); err != nil { 33 return err 34 } 35 } 36 return ig.initStartHeight() 37 } 38 39 // Stop stops the indexer group 40 func (ig *SyncIndexers) Stop(ctx context.Context) error { 41 for _, indexer := range ig.indexers { 42 if err := indexer.Stop(ctx); err != nil { 43 return err 44 } 45 } 46 return nil 47 } 48 49 // PutBlock puts a block into the indexers in the group 50 func (ig *SyncIndexers) PutBlock(ctx context.Context, blk *block.Block) error { 51 for i, indexer := range ig.indexers { 52 // check if the block is higher than the indexer's start height 53 if blk.Height() < ig.startHeights[i] { 54 continue 55 } 56 // check if the block is higher than the indexer's height 57 height, err := indexer.Height() 58 if err != nil { 59 return err 60 } 61 if blk.Height() <= height { 62 continue 63 } 64 // put block 65 if err := indexer.PutBlock(ctx, blk); err != nil { 66 return err 67 } 68 } 69 return nil 70 } 71 72 // DeleteTipBlock deletes the tip block from the indexers in the group 73 func (ig *SyncIndexers) DeleteTipBlock(ctx context.Context, blk *block.Block) error { 74 for _, indexer := range ig.indexers { 75 if err := indexer.DeleteTipBlock(ctx, blk); err != nil { 76 return err 77 } 78 } 79 return nil 80 } 81 82 // StartHeight returns the minimum start height of the indexers in the group 83 func (ig *SyncIndexers) StartHeight() uint64 { 84 return ig.minStartHeight 85 } 86 87 // Height returns the minimum height of the indexers in the group 88 func (ig *SyncIndexers) Height() (uint64, error) { 89 var height uint64 90 for i, indexer := range ig.indexers { 91 h, err := indexer.Height() 92 if err != nil { 93 return 0, err 94 } 95 if i == 0 || h < height { 96 height = h 97 } 98 } 99 return height, nil 100 } 101 102 // initStartHeight initializes the start height of the indexers in the group 103 // for every indexer, the start height is the maximum of tipheight+1 and startheight 104 func (ig *SyncIndexers) initStartHeight() error { 105 ig.minStartHeight = 0 106 ig.startHeights = make([]uint64, len(ig.indexers)) 107 for i, indexer := range ig.indexers { 108 tipHeight, err := indexer.Height() 109 if err != nil { 110 return err 111 } 112 indexStartHeight := tipHeight + 1 113 if indexerWithStart, ok := indexer.(blockdao.BlockIndexerWithStart); ok { 114 startHeight := indexerWithStart.StartHeight() 115 if startHeight > indexStartHeight { 116 indexStartHeight = startHeight 117 } 118 } 119 ig.startHeights[i] = indexStartHeight 120 if i == 0 || indexStartHeight < ig.minStartHeight { 121 ig.minStartHeight = indexStartHeight 122 } 123 } 124 return nil 125 }