github.com/lirm/aeron-go@v0.0.0-20230415210743-920325491dc4/cluster/consensus_module_proxy.go (about) 1 package cluster 2 3 import ( 4 "fmt" 5 6 "github.com/lirm/aeron-go/aeron" 7 "github.com/lirm/aeron-go/aeron/atomic" 8 "github.com/lirm/aeron-go/aeron/idlestrategy" 9 "github.com/lirm/aeron-go/cluster/codecs" 10 ) 11 12 const ( 13 scheduleTimerBlockLength = 16 14 cancelTimerBlockLength = 8 15 ) 16 17 // Proxy class for encapsulating encoding and sending of control protocol messages to a cluster 18 type consensusModuleProxy struct { 19 marshaller *codecs.SbeGoMarshaller // currently shared as we're not reentrant (but could be here) 20 idleStrategy idlestrategy.Idler 21 rangeChecking bool 22 publication *aeron.Publication 23 buffer *atomic.Buffer 24 } 25 26 func newConsensusModuleProxy( 27 options *Options, 28 publication *aeron.Publication, 29 ) *consensusModuleProxy { 30 return &consensusModuleProxy{ 31 marshaller: codecs.NewSbeGoMarshaller(), 32 rangeChecking: options.RangeChecking, 33 publication: publication, 34 buffer: atomic.MakeBuffer(make([]byte, 500)), 35 } 36 } 37 38 // From here we have all the functions that create a data packet and send it on the 39 // publication. Responses will be processed on the control 40 41 // ConnectRequest packet and send 42 func (proxy *consensusModuleProxy) serviceAckRequest( 43 logPosition int64, 44 timestamp int64, 45 ackID int64, 46 relevantID int64, 47 serviceID int32, 48 ) { 49 // Create a packet and send it 50 bytes, err := codecs.ServiceAckRequestPacket( 51 proxy.marshaller, 52 proxy.rangeChecking, 53 logPosition, 54 timestamp, 55 ackID, 56 relevantID, 57 serviceID, 58 ) 59 if err != nil { 60 panic(err) 61 } 62 proxy.send(bytes) 63 } 64 65 func (proxy *consensusModuleProxy) closeSessionRequest( 66 clusterSessionId int64, 67 ) { 68 // Create a packet and send it 69 bytes, err := codecs.CloseSessionRequestPacket( 70 proxy.marshaller, 71 proxy.rangeChecking, 72 clusterSessionId, 73 ) 74 if err != nil { 75 panic(err) 76 } 77 proxy.send(bytes) 78 } 79 80 func (proxy *consensusModuleProxy) scheduleTimer(correlationId int64, deadline int64) bool { 81 buf := proxy.initBuffer(scheduleTimerTemplateId, scheduleTimerBlockLength) 82 buf.PutInt64(SBEHeaderLength, correlationId) 83 buf.PutInt64(SBEHeaderLength+8, deadline) 84 return proxy.offer(buf, 0, SBEHeaderLength+scheduleTimerBlockLength) >= 0 85 } 86 87 func (proxy *consensusModuleProxy) cancelTimer(correlationId int64) bool { 88 buf := proxy.initBuffer(cancelTimerTemplateId, cancelTimerBlockLength) 89 buf.PutInt64(SBEHeaderLength, correlationId) 90 return proxy.offer(buf, 0, SBEHeaderLength+cancelTimerBlockLength) >= 0 91 } 92 93 func (proxy *consensusModuleProxy) initBuffer(templateId uint16, blockLength uint16) *atomic.Buffer { 94 buf := proxy.buffer 95 buf.PutUInt16(0, blockLength) 96 buf.PutUInt16(2, templateId) 97 buf.PutUInt16(4, ClusterSchemaId) 98 buf.PutUInt16(6, ClusterSchemaVersion) 99 return buf 100 } 101 102 // send to our request publication 103 func (proxy *consensusModuleProxy) send(payload []byte) { 104 buffer := atomic.MakeBuffer(payload) 105 for proxy.offer(buffer, 0, buffer.Capacity()) < 0 { 106 proxy.idleStrategy.Idle(0) 107 } 108 } 109 110 func (proxy *consensusModuleProxy) offer(buffer *atomic.Buffer, offset, length int32) int64 { 111 var result int64 112 for i := 0; i < 3; i++ { 113 result = proxy.publication.Offer(buffer, offset, length, nil) 114 if result >= 0 { 115 break 116 } else if result == aeron.NotConnected || result == aeron.PublicationClosed || result == aeron.MaxPositionExceeded { 117 panic(fmt.Sprintf("offer failed, result=%d", result)) 118 } 119 } 120 return result 121 } 122 123 func (proxy *consensusModuleProxy) Offer2( 124 bufferOne *atomic.Buffer, offsetOne int32, lengthOne int32, 125 bufferTwo *atomic.Buffer, offsetTwo int32, lengthTwo int32, 126 ) int64 { 127 var result int64 128 for i := 0; i < 3; i++ { 129 result = proxy.publication.Offer2(bufferOne, offsetOne, lengthOne, bufferTwo, offsetTwo, lengthTwo, nil) 130 if result >= 0 { 131 break 132 } else if result == aeron.NotConnected || result == aeron.PublicationClosed || result == aeron.MaxPositionExceeded { 133 panic(fmt.Sprintf("offer failed, result=%d", result)) 134 } 135 } 136 return result 137 }