github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/store_heads.go (about)

     1  package gossip
     2  
     3  import (
     4  	"bytes"
     5  	"sort"
     6  
     7  	"github.com/unicornultrafoundation/go-helios/hash"
     8  	"github.com/unicornultrafoundation/go-helios/native/idx"
     9  
    10  	"github.com/unicornultrafoundation/go-u2u/utils/concurrent"
    11  )
    12  
    13  type sortedHead []byte
    14  
    15  func (es *epochStore) getCachedHeads() (*concurrent.EventsSet, bool) {
    16  	cache := es.cache.Heads.Load()
    17  	if cache != nil {
    18  		return cache.(*concurrent.EventsSet), true
    19  	}
    20  	return nil, false
    21  }
    22  
    23  func (es *epochStore) loadHeads() *concurrent.EventsSet {
    24  	res := make(hash.EventsSet, 100)
    25  
    26  	b, err := es.table.Heads.Get([]byte{})
    27  	if err != nil {
    28  		es.Log.Crit("Failed to get key-value", "err", err)
    29  	}
    30  	if b == nil {
    31  		return concurrent.WrapEventsSet(res)
    32  	}
    33  	for i := 0; i < len(b); i += 32 {
    34  		res.Add(hash.BytesToEvent(b[i : i+32]))
    35  	}
    36  
    37  	return concurrent.WrapEventsSet(res)
    38  }
    39  
    40  func (es *epochStore) GetHeads() *concurrent.EventsSet {
    41  	cached, ok := es.getCachedHeads()
    42  	if ok {
    43  		return cached
    44  	}
    45  	heads := es.loadHeads()
    46  	if heads == nil {
    47  		heads = &concurrent.EventsSet{}
    48  	}
    49  	es.cache.Heads.Store(heads)
    50  	return heads
    51  }
    52  
    53  func (es *epochStore) SetHeads(ids *concurrent.EventsSet) {
    54  	es.cache.Heads.Store(ids)
    55  }
    56  
    57  func (es *epochStore) FlushHeads() {
    58  	ids, ok := es.getCachedHeads()
    59  	if !ok {
    60  		return
    61  	}
    62  
    63  	// sort values for determinism
    64  	sortedHeads := make([]sortedHead, 0, len(ids.Val))
    65  	for id := range ids.Val {
    66  		sortedHeads = append(sortedHeads, id.Bytes())
    67  	}
    68  	sort.Slice(sortedHeads, func(i, j int) bool {
    69  		a, b := sortedHeads[i], sortedHeads[j]
    70  		return bytes.Compare(a, b) < 0
    71  	})
    72  
    73  	b := make([]byte, 0, len(sortedHeads)*32)
    74  	for _, head := range sortedHeads {
    75  		b = append(b, head...)
    76  	}
    77  
    78  	if err := es.table.Heads.Put([]byte{}, b); err != nil {
    79  		es.Log.Crit("Failed to put key-value", "err", err)
    80  	}
    81  }
    82  
    83  // GetHeadsSlice returns IDs of all the epoch events with no descendants
    84  func (s *Store) GetHeadsSlice(epoch idx.Epoch) hash.Events {
    85  	heads := s.GetHeads(epoch)
    86  	heads.RLock()
    87  	defer heads.RUnlock()
    88  	return heads.Val.Slice()
    89  }
    90  
    91  // GetHeads returns set of all the epoch event IDs with no descendants
    92  func (s *Store) GetHeads(epoch idx.Epoch) *concurrent.EventsSet {
    93  	es := s.getEpochStore(epoch)
    94  	if es == nil {
    95  		return nil
    96  	}
    97  
    98  	return es.GetHeads()
    99  }
   100  
   101  func (s *Store) SetHeads(epoch idx.Epoch, ids *concurrent.EventsSet) {
   102  	es := s.getEpochStore(epoch)
   103  	if es == nil {
   104  		return
   105  	}
   106  
   107  	es.SetHeads(ids)
   108  }