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 }