github.com/iotexproject/iotex-core@v1.14.1-rc1/blockchain/filedao/filedao_v2_manager.go (about) 1 package filedao 2 3 import ( 4 "context" 5 "sort" 6 7 "github.com/iotexproject/go-pkgs/hash" 8 9 "github.com/iotexproject/iotex-core/blockchain/block" 10 "github.com/iotexproject/iotex-core/db" 11 ) 12 13 type ( 14 fileV2Index struct { 15 start, end uint64 16 fd *fileDAOv2 17 } 18 19 // FileV2Manager manages collection of v2 files 20 FileV2Manager struct { 21 Indices []*fileV2Index 22 } 23 ) 24 25 // newFileV2Manager creates an instance of FileV2Manager 26 func newFileV2Manager(fds []*fileDAOv2) (*FileV2Manager, error) { 27 if len(fds) == 0 { 28 return nil, ErrNotSupported 29 } 30 31 fm := FileV2Manager{ 32 Indices: make([]*fileV2Index, len(fds)), 33 } 34 for i := range fds { 35 fm.Indices[i] = &fileV2Index{fd: fds[i]} 36 } 37 return &fm, nil 38 } 39 40 // Start starts the FileV2Manager 41 func (fm *FileV2Manager) Start(ctx context.Context) error { 42 for i := range fm.Indices { 43 fd := fm.Indices[i].fd 44 if err := fd.Start(ctx); err != nil { 45 return err 46 } 47 48 // check start/end height 49 start, err := fd.Bottom() 50 if err != nil { 51 return err 52 } 53 54 end, err := fd.Height() 55 if err != nil { 56 return err 57 } 58 fm.Indices[i].start = start 59 fm.Indices[i].end = end 60 } 61 sort.Slice(fm.Indices, func(i, j int) bool { return fm.Indices[i].start < fm.Indices[j].start }) 62 return nil 63 } 64 65 // Stop stops the FileV2Manager 66 func (fm *FileV2Manager) Stop(ctx context.Context) error { 67 for i := range fm.Indices { 68 if err := fm.Indices[i].fd.Stop(ctx); err != nil { 69 return err 70 } 71 } 72 return nil 73 } 74 75 // FileDAOByHeight returns FileDAO for the given height 76 func (fm *FileV2Manager) FileDAOByHeight(height uint64) BaseFileDAO { 77 if height == 0 { 78 return fm.Indices[0].fd 79 } 80 right := len(fm.Indices) - 1 81 if height >= fm.Indices[right].start { 82 return fm.Indices[right].fd 83 } 84 85 left := 0 86 for left <= right { 87 mid := (left + right) / 2 88 v := fm.Indices[mid] 89 if v.start <= height && height <= v.end { 90 return v.fd 91 } 92 if height < v.start { 93 right = mid - 1 94 } else { 95 left = mid + 1 96 } 97 } 98 return nil 99 } 100 101 // GetBlockHeight returns height by hash 102 func (fm *FileV2Manager) GetBlockHeight(hash hash.Hash256) (uint64, error) { 103 for _, file := range fm.Indices { 104 if height, err := file.fd.GetBlockHeight(hash); err == nil { 105 return height, nil 106 } 107 } 108 return 0, db.ErrNotExist 109 } 110 111 // GetBlock returns block by hash 112 func (fm *FileV2Manager) GetBlock(hash hash.Hash256) (*block.Block, error) { 113 for _, file := range fm.Indices { 114 if blk, err := file.fd.GetBlock(hash); err == nil { 115 return blk, nil 116 } 117 } 118 return nil, db.ErrNotExist 119 } 120 121 // AddFileDAO add a new v2 file 122 func (fm *FileV2Manager) AddFileDAO(fd *fileDAOv2, start uint64) error { 123 // update current top's end 124 top := fm.Indices[len(fm.Indices)-1] 125 end, err := top.fd.Height() 126 if err != nil { 127 return err 128 } 129 if start != end+1 { 130 // new file's first block != current tip height 131 return ErrInvalidTipHeight 132 } 133 134 top.end = end 135 fm.Indices = append(fm.Indices, &fileV2Index{fd: fd, start: start, end: end}) 136 return nil 137 } 138 139 // TopFd returns the top (with maximum height) v2 file 140 func (fm *FileV2Manager) TopFd() (BaseFileDAO, uint64) { 141 top := fm.Indices[len(fm.Indices)-1] 142 return top.fd, top.start 143 }