github.com/lirm/aeron-go@v0.0.0-20230415210743-920325491dc4/archive/recordingevents.go (about) 1 // Copyright (C) 2021-2022 Talos, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package archive 16 17 import ( 18 "bytes" 19 "fmt" 20 21 "github.com/lirm/aeron-go/aeron" 22 "github.com/lirm/aeron-go/aeron/atomic" 23 "github.com/lirm/aeron-go/aeron/logbuffer" 24 "github.com/lirm/aeron-go/aeron/logbuffer/term" 25 "github.com/lirm/aeron-go/archive/codecs" 26 ) 27 28 // RecordingEventsAdapter is used to poll for recording events on a subscription. 29 type RecordingEventsAdapter struct { 30 Subscription *aeron.Subscription 31 Enabled bool 32 archive *Archive // link to parent 33 34 pollFunc term.FragmentHandler 35 handlerWithListeners FragmentHandlerWithListeners 36 reFragmentHandlerFunc FragmentHandlerWithListeners 37 buf *bytes.Buffer 38 marshaller *codecs.SbeGoMarshaller 39 } 40 41 // FragmentHandlerWithListeners provides a FragmentHandler with ArchiveListeners 42 type FragmentHandlerWithListeners func(listeners *ArchiveListeners, buffer *atomic.Buffer, offset int32, length int32, header *logbuffer.Header) 43 44 // PollWithContext the aeron subscription handler. 45 // If you pass it a nil handler it will use the builtin and call the Listeners 46 // If you ask for 0 fragments it will only return one fragment (if available) 47 func (rea *RecordingEventsAdapter) PollWithContext(handler FragmentHandlerWithListeners, fragmentLimit int) int { 48 if rea.pollFunc == nil { 49 rea.prealloc() 50 } 51 52 // Update our globals in case they've changed so we use the current state in our callback 53 rangeChecking = rea.archive.Options.RangeChecking 54 55 if handler != nil { 56 rea.handlerWithListeners = handler 57 } else { 58 rea.handlerWithListeners = rea.reFragmentHandlerFunc 59 } 60 if fragmentLimit == 0 { 61 fragmentLimit = 1 62 } 63 return rea.Subscription.Poll(rea.pollFunc, fragmentLimit) 64 } 65 66 func (rea *RecordingEventsAdapter) prealloc() { 67 rea.pollFunc = func(buf *atomic.Buffer, offset int32, length int32, header *logbuffer.Header) { 68 rea.handlerWithListeners(rea.archive.Listeners, buf, offset, length, header) 69 } 70 rea.reFragmentHandlerFunc = rea.reFragmentHandler 71 } 72 73 func (rea *RecordingEventsAdapter) reFragmentHandler(listeners *ArchiveListeners, buffer *atomic.Buffer, offset int32, length int32, header *logbuffer.Header) { 74 var hdr codecs.SbeGoMessageHeader 75 76 if rea.buf == nil { 77 rea.buf = new(bytes.Buffer) 78 } 79 buf := rea.buf 80 rea.buf.Reset() 81 buffer.WriteBytes(rea.buf, offset, length) 82 83 if rea.marshaller == nil { 84 rea.marshaller = codecs.NewSbeGoMarshaller() 85 } 86 marshaller := rea.marshaller 87 88 if err := hdr.Decode(marshaller, buf); err != nil { 89 // Not much to be done here as we can't correlate 90 err2 := fmt.Errorf("reFragmentHandler() failed to decode control message header: %w", err) 91 // Call the global error handler, ugly but it's all we've got 92 if listeners.ErrorListener != nil { 93 listeners.ErrorListener(err2) 94 } 95 } 96 97 switch hdr.TemplateId { 98 case codecIds.recordingStarted: 99 var recordingStarted = new(codecs.RecordingStarted) 100 logger.Debugf("Received RecordingStarted: length %d", buf.Len()) 101 if err := recordingStarted.Decode(marshaller, buf, hdr.Version, hdr.BlockLength, rangeChecking); err != nil { 102 err2 := fmt.Errorf("Decode() of RecordingStarted failed: %w", err) 103 if listeners.ErrorListener != nil { 104 listeners.ErrorListener(err2) 105 } 106 } else { 107 // logger.Debugf("RecordingStarted: %#v\n", recordingStarted) 108 // Call the Listener 109 if listeners.RecordingEventStartedListener != nil { 110 listeners.RecordingEventStartedListener(recordingStarted) 111 } 112 } 113 114 case codecIds.recordingProgress: 115 var recordingProgress = new(codecs.RecordingProgress) 116 logger.Debugf("Received RecordingProgress: length %d", buf.Len()) 117 if err := recordingProgress.Decode(marshaller, buf, hdr.Version, hdr.BlockLength, rangeChecking); err != nil { 118 err2 := fmt.Errorf("Decode() of RecordingProgress failed: %w", err) 119 if listeners.ErrorListener != nil { 120 listeners.ErrorListener(err2) 121 } 122 } else { 123 logger.Debugf("RecordingProgress: %#v", recordingProgress) 124 // Call the Listener 125 if listeners.RecordingEventProgressListener != nil { 126 listeners.RecordingEventProgressListener(recordingProgress) 127 } 128 } 129 130 case codecIds.recordingStopped: 131 var recordingStopped = new(codecs.RecordingStopped) 132 logger.Debugf("Received RecordingStopped: length %d", buf.Len()) 133 if err := recordingStopped.Decode(marshaller, buf, hdr.Version, hdr.BlockLength, rangeChecking); err != nil { 134 err2 := fmt.Errorf("Decode() of RecordingStopped failed: %w", err) 135 if listeners.ErrorListener != nil { 136 listeners.ErrorListener(err2) 137 } 138 } else { 139 logger.Debugf("RecordingStopped: %#v", recordingStopped) 140 // Call the Listener 141 if listeners.RecordingEventStoppedListener != nil { 142 listeners.RecordingEventStoppedListener(recordingStopped) 143 } 144 } 145 146 default: 147 logger.Errorf("Insert decoder for type: %d", hdr.TemplateId) 148 } 149 }