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  }