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  }