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

     1  // Licensed under the Apache License, Version 2.0 (the "License");
     2  // you may not use this file except in compliance with the License.
     3  // You may obtain a copy of the License at
     4  //
     5  // http://www.apache.org/licenses/LICENSE-2.0
     6  //
     7  // Unless required by applicable law or agreed to in writing, software
     8  // distributed under the License is distributed on an "AS IS" BASIS,
     9  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    10  // See the License for the specific language governing permissions and
    11  // limitations under the License.
    12  
    13  package cluster
    14  
    15  import (
    16  	"bytes"
    17  	"github.com/lirm/aeron-go/aeron"
    18  	"github.com/lirm/aeron-go/aeron/atomic"
    19  	"github.com/lirm/aeron-go/aeron/logbuffer"
    20  	"github.com/lirm/aeron-go/cluster/codecs"
    21  )
    22  
    23  const (
    24  	beginFrag    uint8 = 0x80
    25  	endFrag      uint8 = 0x40
    26  	unfragmented uint8 = 0x80 | 0x40
    27  )
    28  
    29  type boundedLogAdapter struct {
    30  	marshaller     *codecs.SbeGoMarshaller
    31  	options        *Options
    32  	agent          *ClusteredServiceAgent
    33  	image          aeron.Image
    34  	builder        *bytes.Buffer
    35  	maxLogPosition int64
    36  }
    37  
    38  func (adapter *boundedLogAdapter) isDone() bool {
    39  	return adapter.image.Position() >= adapter.maxLogPosition ||
    40  		adapter.image.IsEndOfStream() ||
    41  		adapter.image.IsClosed()
    42  }
    43  
    44  func (adapter *boundedLogAdapter) poll(limitPos int64) int {
    45  	return adapter.image.BoundedPoll(adapter.onFragment, limitPos, adapter.options.LogFragmentLimit)
    46  }
    47  
    48  func (adapter *boundedLogAdapter) onFragment(
    49  	buffer *atomic.Buffer,
    50  	offset int32,
    51  	length int32,
    52  	header *logbuffer.Header,
    53  ) {
    54  	flags := header.Flags()
    55  	if (flags & unfragmented) == unfragmented {
    56  		adapter.onMessage(buffer, offset, length, header)
    57  	} else if (flags & beginFrag) == beginFrag {
    58  		if adapter.builder == nil {
    59  			adapter.builder = &bytes.Buffer{}
    60  		}
    61  		adapter.builder.Reset()
    62  		buffer.WriteBytes(adapter.builder, offset, length)
    63  	} else if adapter.builder != nil && adapter.builder.Len() != 0 {
    64  		buffer.WriteBytes(adapter.builder, offset, length)
    65  		if (flags & endFrag) == endFrag {
    66  			msgLength := adapter.builder.Len()
    67  			adapter.onMessage(
    68  				atomic.MakeBuffer(adapter.builder.Bytes(), msgLength),
    69  				int32(0),
    70  				int32(msgLength),
    71  				header)
    72  			adapter.builder.Reset()
    73  		}
    74  	}
    75  }
    76  
    77  func (adapter *boundedLogAdapter) onMessage(
    78  	buffer *atomic.Buffer,
    79  	offset int32,
    80  	length int32,
    81  	header *logbuffer.Header,
    82  ) {
    83  	if length < SBEHeaderLength {
    84  		return
    85  	}
    86  	blockLength := buffer.GetUInt16(offset)
    87  	templateId := buffer.GetUInt16(offset + 2)
    88  	schemaId := buffer.GetUInt16(offset + 4)
    89  	version := buffer.GetUInt16(offset + 6)
    90  	if schemaId != ClusterSchemaId {
    91  		logger.Errorf("BoundedLogAdaptor - unexpected schemaId=%d templateId=%d blockLen=%d version=%d",
    92  			schemaId, templateId, blockLength, version)
    93  		return
    94  	}
    95  	offset += SBEHeaderLength
    96  	length -= SBEHeaderLength
    97  
    98  	switch templateId {
    99  	case timerEventTemplateId:
   100  		correlationId := buffer.GetInt64(offset + 8)
   101  		timestamp := buffer.GetInt64(offset + 16)
   102  		adapter.agent.onTimerEvent(header.Position(), correlationId, timestamp)
   103  	case sessionOpenTemplateId:
   104  		event := &codecs.SessionOpenEvent{}
   105  		if err := event.Decode(
   106  			adapter.marshaller,
   107  			toByteBuffer(buffer, offset, length),
   108  			version,
   109  			blockLength,
   110  			adapter.options.RangeChecking,
   111  		); err != nil {
   112  			logger.Errorf("boundedLogAdapter: session open decode error: %v", err)
   113  			return
   114  		}
   115  
   116  		err := adapter.agent.onSessionOpen(
   117  			event.LeadershipTermId,
   118  			header.Position(),
   119  			event.ClusterSessionId,
   120  			event.Timestamp,
   121  			event.ResponseStreamId,
   122  			string(event.ResponseChannel),
   123  			event.EncodedPrincipal,
   124  		)
   125  		if err != nil {
   126  			panic("boundedLogAdapter: session open error: " + err.Error())
   127  		}
   128  	case sessionCloseTemplateId:
   129  		leadershipTermId := buffer.GetInt64(offset)
   130  		clusterSessionId := buffer.GetInt64(offset + 8)
   131  		timestamp := buffer.GetInt64(offset + 16)
   132  		closeReason := codecs.CloseReasonEnum(buffer.GetInt32(offset + 24))
   133  		adapter.agent.onSessionClose(leadershipTermId, header.Position(), clusterSessionId, timestamp, closeReason)
   134  	case clusterActionReqTemplateId:
   135  		e := codecs.ClusterActionRequest{}
   136  		buf := toByteBuffer(buffer, offset, length)
   137  		if err := e.Decode(adapter.marshaller, buf, version, blockLength, adapter.options.RangeChecking); err != nil {
   138  			logger.Errorf("boundedLogAdapter: cluster action request decode error: %v", err)
   139  		} else {
   140  			adapter.agent.onServiceAction(e.LeadershipTermId, e.LogPosition, e.Timestamp, e.Action)
   141  		}
   142  	case newLeadershipTermTemplateId:
   143  		e := codecs.NewLeadershipTermEvent{}
   144  		buf := toByteBuffer(buffer, offset, length)
   145  		if err := e.Decode(adapter.marshaller, buf, version, blockLength, adapter.options.RangeChecking); err != nil {
   146  			logger.Errorf("boundedLogAdapter: new leadership term decode error: %v", err)
   147  		} else {
   148  			adapter.agent.onNewLeadershipTermEvent(e.LeadershipTermId, e.LogPosition, e.Timestamp,
   149  				e.TermBaseLogPosition, e.LeaderMemberId, e.LogSessionId, e.TimeUnit, e.AppVersion)
   150  		}
   151  	case membershipChangeTemplateId:
   152  		e := codecs.MembershipChangeEvent{}
   153  		buf := toByteBuffer(buffer, offset, length)
   154  		if err := e.Decode(adapter.marshaller, buf, version, blockLength, adapter.options.RangeChecking); err != nil {
   155  			logger.Errorf("boundedLogAdapter: membership change event decode error: %v", err)
   156  		} else {
   157  			adapter.agent.onMembershipChange(e.LogPosition, e.Timestamp, e.ChangeType, e.MemberId)
   158  		}
   159  	case SessionMessageHeaderTemplateId:
   160  		if length < SessionMessageHeaderLength {
   161  			logger.Errorf("received invalid session message - length: %d", length)
   162  			return
   163  		}
   164  		clusterSessionId := buffer.GetInt64(offset + 8)
   165  		timestamp := buffer.GetInt64(offset + 16)
   166  		adapter.agent.onSessionMessage(
   167  			header.Position(),
   168  			clusterSessionId,
   169  			timestamp,
   170  			buffer,
   171  			offset+SessionMessageHeaderLength,
   172  			length-SessionMessageHeaderLength,
   173  			header,
   174  		)
   175  	default:
   176  		logger.Debugf("BoundedLogAdaptor: unexpected templateId=%d at pos=%d", templateId, header.Position())
   177  	}
   178  }
   179  
   180  func toByteBuffer(buffer *atomic.Buffer, offset int32, length int32) *bytes.Buffer {
   181  	buf := &bytes.Buffer{}
   182  	buffer.WriteBytes(buf, offset, length)
   183  	return buf
   184  }
   185  
   186  func (adapter *boundedLogAdapter) Close() error {
   187  	var err error
   188  	if adapter.image != nil {
   189  		err = adapter.image.Close()
   190  		adapter.image = nil
   191  	}
   192  	return err
   193  }