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 }