gitee.com/lh-her-team/common@v1.5.1/birdsnest/serialize.go (about)

     1  // Package birdsnest serialize
     2  package birdsnest
     3  
     4  import (
     5  	"encoding/json"
     6  	"reflect"
     7  	"time"
     8  
     9  	birdsnestpb "gitee.com/lh-her-team/common/birdsnest/pb"
    10  
    11  	"github.com/gogo/protobuf/proto"
    12  )
    13  
    14  // TODO Split BirdsNestImpl and Serialize
    15  
    16  // Start serialize monitor TODO Goroutinue should be turned off using context.Context here
    17  func (b *BirdsNestImpl) Start() {
    18  	go b.serializeMonitor()
    19  	go b.serializeTimed()
    20  }
    21  
    22  // serializeMonitor
    23  func (b *BirdsNestImpl) serializeMonitor() {
    24  	for { // nolint
    25  		select {
    26  		// Only signals for the current filter "serialized type" are received
    27  		case signal := <-b.serializeC:
    28  			t, ok := SerializeIntervalType_name[signal.typ]
    29  			if !ok {
    30  				b.log.Errorf("serialize type %v not support", t)
    31  			}
    32  			switch signal.typ {
    33  			case SerializeIntervalType_Height:
    34  				// current height - pre height < height interval does not serialize; otherwise, it serialize
    35  				// eg: 85 - 80 = 5 < 10
    36  				// 	   5 < 10 true does not serialize
    37  				if b.height-b.preHeight.Load() < b.config.Snapshot.BlockHeight.Interval {
    38  					continue
    39  				}
    40  			case SerializeIntervalType_Timed, SerializeIntervalType_Exit:
    41  				// common.SerializeIntervalType_Timed and common.SerializeIntervalType_Exit are handled directly
    42  			default:
    43  				continue
    44  			}
    45  			err := b.Serialize()
    46  			if err != nil {
    47  				b.log.Errorf("serialize error type: %v, error: %v", t, err)
    48  			}
    49  		}
    50  	}
    51  }
    52  
    53  // Serialize all cuckoos in the current BirdsNest
    54  func (b *BirdsNestImpl) Serialize() error {
    55  	t := time.Now()
    56  	// Logs are print after the method is complete
    57  	defer func(log Logger) {
    58  		elapsed := time.Since(t)
    59  		log.Debugf("bird's nest serialize success elapsed: %v", elapsed)
    60  	}(b.log)
    61  	// convert []CuckooFilter to []*common.CuckooFilter
    62  	var filters []*birdsnestpb.CuckooFilter
    63  	filters, err := analysisCuckooFilters(b.filters)
    64  	if err != nil {
    65  		return err
    66  	}
    67  	marshal, err := json.Marshal(b.config)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	birdsNest := &birdsnestpb.BirdsNest{
    72  		Config:       marshal,
    73  		Height:       b.preHeight.Load(),
    74  		CurrentIndex: uint32(b.currentIndex),
    75  		Filters:      filters,
    76  	}
    77  	data, err := proto.Marshal(birdsNest)
    78  	if err != nil {
    79  		return err
    80  	}
    81  	// Write to disk
    82  	err = b.snapshot.Write(data)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	// Increase the height
    87  	b.preHeight.Store(b.height)
    88  	return nil
    89  }
    90  
    91  // Deserialize deserialize Bird's nest
    92  func (b *BirdsNestImpl) Deserialize() error {
    93  	data, err := b.snapshot.Read()
    94  	if err != nil {
    95  		return err
    96  	}
    97  	if data == nil {
    98  		return nil
    99  	}
   100  	var bn = new(birdsnestpb.BirdsNest)
   101  	err = proto.Unmarshal(data, bn)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	filters, err := newCuckooFiltersByDecode(bn.Filters)
   106  	if err != nil {
   107  		return err
   108  	}
   109  	var bnConfig BirdsNestConfig
   110  	err = json.Unmarshal(bn.Config, &bnConfig)
   111  	if err != nil {
   112  		return err
   113  	}
   114  	if !reflect.DeepEqual(bnConfig, b.config) {
   115  		err = ErrCannotModifyTheNestConfiguration
   116  	}
   117  	b.filters = filters
   118  	b.config = &bnConfig
   119  	b.height = bn.Height
   120  	b.currentIndex = int(bn.CurrentIndex)
   121  	return err
   122  }
   123  
   124  // serializeTimed send SerializeIntervalType_Timed sign
   125  func (b *BirdsNestImpl) serializeTimed() {
   126  	if b.config.Snapshot.Type != SerializeIntervalType_Timed {
   127  		return
   128  	}
   129  	ticker := time.NewTicker(time.Second * time.Duration(b.config.Snapshot.Timed.Interval))
   130  	// nolint
   131  	for {
   132  		select {
   133  		case <-ticker.C:
   134  			b.serializeC <- serializeSignal{typ: SerializeIntervalType_Timed}
   135  		}
   136  	}
   137  }
   138  
   139  // serializeExit send SerializeIntervalType_Exit sign
   140  // nolint: unused
   141  func (b *BirdsNestImpl) serializeExit() {
   142  	b.serializeC <- serializeSignal{typ: SerializeIntervalType_Exit}
   143  }
   144  
   145  // serializeHeight send SerializeIntervalType_Height sign
   146  func (b *BirdsNestImpl) serializeHeight(height uint64) {
   147  	if b.config.Snapshot.Type != SerializeIntervalType_Height {
   148  		return
   149  	}
   150  	b.serializeC <- serializeSignal{typ: SerializeIntervalType_Height, height: height}
   151  }
   152  
   153  // Serialize signal
   154  type serializeSignal struct {
   155  	typ    SerializeIntervalType
   156  	height uint64
   157  }