github.com/lirm/aeron-go@v0.0.0-20230415210743-920325491dc4/cluster/snapshot_taker.go (about)

     1  package cluster
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/lirm/aeron-go/aeron"
     8  	"github.com/lirm/aeron-go/aeron/atomic"
     9  	"github.com/lirm/aeron-go/cluster/codecs"
    10  )
    11  
    12  const snapshotTypeId = 2
    13  
    14  type snapshotTaker struct {
    15  	marshaller  *codecs.SbeGoMarshaller // currently shared as we're not reentrant (but could be here)
    16  	options     *Options
    17  	publication *aeron.Publication
    18  }
    19  
    20  func newSnapshotTaker(
    21  	options *Options,
    22  	publication *aeron.Publication,
    23  ) *snapshotTaker {
    24  	return &snapshotTaker{
    25  		marshaller:  codecs.NewSbeGoMarshaller(),
    26  		options:     options,
    27  		publication: publication,
    28  	}
    29  }
    30  
    31  func (st *snapshotTaker) markBegin(
    32  	logPosition int64,
    33  	leadershipTermId int64,
    34  	timeUnit codecs.ClusterTimeUnitEnum,
    35  	appVersion int32,
    36  ) error {
    37  	return st.markSnapshot(logPosition, leadershipTermId, codecs.SnapshotMark.BEGIN, timeUnit, appVersion)
    38  }
    39  
    40  func (st *snapshotTaker) markEnd(
    41  	logPosition int64,
    42  	leadershipTermId int64,
    43  	timeUnit codecs.ClusterTimeUnitEnum,
    44  	appVersion int32,
    45  ) error {
    46  	return st.markSnapshot(logPosition, leadershipTermId, codecs.SnapshotMark.END, timeUnit, appVersion)
    47  }
    48  
    49  func (st *snapshotTaker) markSnapshot(
    50  	logPosition int64,
    51  	leadershipTermId int64,
    52  	mark codecs.SnapshotMarkEnum,
    53  	timeUnit codecs.ClusterTimeUnitEnum,
    54  	appVersion int32,
    55  ) error {
    56  	bytes, err := codecs.SnapshotMarkerPacket(
    57  		st.marshaller,
    58  		st.options.RangeChecking,
    59  		snapshotTypeId,
    60  		logPosition,
    61  		leadershipTermId,
    62  		0,
    63  		mark,
    64  		timeUnit,
    65  		appVersion,
    66  	)
    67  	if err != nil {
    68  		return err
    69  	}
    70  	if ret := st.offer(bytes); ret < 0 {
    71  		return fmt.Errorf("snapshotTaker.offer failed: %d", ret)
    72  	}
    73  	return nil
    74  }
    75  
    76  func (st *snapshotTaker) snapshotSession(session ClientSession) error {
    77  	bytes, err := codecs.ClientSessionPacket(st.marshaller, st.options.RangeChecking,
    78  		session.Id(), session.ResponseStreamId(), []byte(session.ResponseChannel()), session.EncodedPrincipal())
    79  	if err != nil {
    80  		return err
    81  	}
    82  	if ret := st.offer(bytes); ret < 0 {
    83  		return fmt.Errorf("snapshotTaker.offer failed: %d", ret)
    84  	}
    85  	return nil
    86  }
    87  
    88  // Offer to our request publication
    89  func (st *snapshotTaker) offer(bytes []byte) int64 {
    90  	buffer := atomic.MakeBuffer(bytes)
    91  	length := int32(len(bytes))
    92  	start := time.Now()
    93  	var ret int64
    94  	for time.Since(start) < st.options.Timeout {
    95  		ret = st.publication.Offer(buffer, 0, length, nil)
    96  		switch ret {
    97  		// Retry on these
    98  		case aeron.NotConnected, aeron.BackPressured, aeron.AdminAction:
    99  			st.options.IdleStrategy.Idle(0)
   100  		// Fail or succeed on other values
   101  		default:
   102  			return ret
   103  		}
   104  	}
   105  	// Give up, returning the last failure
   106  	return ret
   107  }