github.com/lirm/aeron-go@v0.0.0-20230415210743-920325491dc4/archive/examples/basic_replay_merge/basic_replay_merge.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  // An example replayed subscriber
    16  package main
    17  
    18  import (
    19  	"flag"
    20  	"fmt"
    21  	"time"
    22  
    23  	"github.com/lirm/aeron-go/aeron"
    24  	"github.com/lirm/aeron-go/aeron/atomic"
    25  	"github.com/lirm/aeron-go/aeron/idlestrategy"
    26  	"github.com/lirm/aeron-go/aeron/logbuffer"
    27  	"github.com/lirm/aeron-go/aeron/logging"
    28  	"github.com/lirm/aeron-go/archive"
    29  	"github.com/lirm/aeron-go/archive/codecs"
    30  	"github.com/lirm/aeron-go/archive/examples"
    31  	"github.com/lirm/aeron-go/archive/replaymerge"
    32  )
    33  
    34  var logID = "basic_replay_merge"
    35  var logger = logging.MustGetLogger(logID)
    36  
    37  func main() {
    38  	flag.Parse()
    39  
    40  	sampleChannel := *examples.Config.MdcChannel
    41  	sampleStream := int32(*examples.Config.SampleStream)
    42  	responseStream := sampleStream + 2
    43  
    44  	timeout := time.Duration(time.Millisecond.Nanoseconds() * *examples.Config.DriverTimeout)
    45  	context := aeron.NewContext().
    46  		AeronDir(*examples.Config.AeronPrefix).
    47  		MediaDriverTimeout(timeout).
    48  		AvailableImageHandler(func(image aeron.Image) {
    49  			logger.Infof("Image available: %+v", image)
    50  		}).
    51  		UnavailableImageHandler(func(image aeron.Image) {
    52  			logger.Infof("Image unavailable: %+v", image)
    53  		}).
    54  		ErrorHandler(func(err error) {
    55  			logger.Warning(err)
    56  		})
    57  
    58  	options := archive.DefaultOptions()
    59  	options.RequestChannel = *examples.Config.RequestChannel
    60  	options.RequestStream = int32(*examples.Config.RequestStream)
    61  	options.ResponseChannel = *examples.Config.ResponseChannel
    62  	options.ResponseStream = responseStream
    63  
    64  	t := false
    65  	examples.Config.Verbose = &t
    66  	if *examples.Config.Verbose {
    67  		fmt.Printf("Setting loglevel: archive.DEBUG/aeron.INFO\n")
    68  		options.ArchiveLoglevel = logging.DEBUG
    69  		options.AeronLoglevel = logging.DEBUG
    70  		logging.SetLevel(logging.DEBUG, logID)
    71  	} else {
    72  		logging.SetLevel(logging.NOTICE, logID)
    73  	}
    74  
    75  	arch, err := archive.NewArchive(options, context)
    76  	if err != nil {
    77  		logger.Fatalf("Failed to connect to media driver: %s\n", err.Error())
    78  	}
    79  	defer arch.Close()
    80  
    81  	// Enable recording events although the defaults will only log in debug mode
    82  	arch.EnableRecordingEvents()
    83  
    84  	recording, err := FindLatestRecording(arch, sampleChannel, sampleStream)
    85  	if err != nil {
    86  		logger.Fatalf(err.Error())
    87  	}
    88  
    89  	subChannelUri, _ := aeron.ParseChannelUri("aeron:udp")
    90  	subChannelUri.SetControlMode(aeron.MdcControlModeManual)
    91  	subChannelUri.SetSessionID(recording.SessionId)
    92  	subChannel := subChannelUri.String()
    93  
    94  	logger.Infof("Subscribing to channel:%s, stream:%d", subChannel, sampleStream)
    95  	subscription, err := arch.AddSubscription(subChannel, sampleStream)
    96  	if err != nil {
    97  		logger.Fatal(err)
    98  	}
    99  	defer subscription.Close()
   100  
   101  	counter := 0
   102  	printHandler := func(buffer *atomic.Buffer, offset int32, length int32, header *logbuffer.Header) {
   103  		bytes := buffer.GetBytesArray(offset, length)
   104  		logger.Infof("Message: %s", bytes)
   105  		counter++
   106  	}
   107  
   108  	idleStrategy := idlestrategy.Sleeping{SleepFor: time.Millisecond * 100}
   109  
   110  	liveDestination := sampleChannel
   111  
   112  	replayDestinationUri, _ := aeron.ParseChannelUri("aeron:udp?endpoint=localhost:0")
   113  	replayDestination := replayDestinationUri.String()
   114  
   115  	replayChannelUri, _ := aeron.ParseChannelUri(replayDestination)
   116  	replayChannelUri.SetSessionID(recording.SessionId)
   117  	replayChannel := replayChannelUri.String()
   118  
   119  	logger.Infof(
   120  		"ReplayMerge(subChannel:%s,%d,replayChannel:%s,replayDestination:%s,liveDestination:%s)",
   121  		subscription.Channel(),
   122  		subscription.StreamID(),
   123  		replayChannel,
   124  		replayDestination,
   125  		liveDestination,
   126  	)
   127  	merge, err := replaymerge.NewReplayMerge(
   128  		subscription,
   129  		arch,
   130  		replayChannel,
   131  		replayDestination,
   132  		liveDestination,
   133  		recording.RecordingId,
   134  		0,
   135  		5000,
   136  	)
   137  	if err != nil {
   138  		logger.Fatalf(err.Error())
   139  	}
   140  	defer merge.Close()
   141  
   142  	var fragmentsRead int
   143  	for !merge.IsMerged() {
   144  		fragmentsRead, err = merge.Poll(printHandler, 10)
   145  		if err != nil {
   146  			logger.Fatalf(err.Error())
   147  		}
   148  		arch.RecordingEventsPoll()
   149  		idleStrategy.Idle(fragmentsRead)
   150  	}
   151  
   152  	merge.Close()
   153  
   154  	for {
   155  		fragmentsRead := subscription.Poll(printHandler, 10)
   156  		arch.RecordingEventsPoll()
   157  
   158  		idleStrategy.Idle(fragmentsRead)
   159  	}
   160  }
   161  
   162  // FindLatestRecording to lookup the last recording
   163  func FindLatestRecording(arch *archive.Archive, channel string, stream int32) (*codecs.RecordingDescriptor, error) {
   164  	descriptors, err := arch.ListRecordingsForUri(0, 100, "", stream)
   165  
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  
   170  	if len(descriptors) == 0 {
   171  		return nil, fmt.Errorf("no recordings found")
   172  	}
   173  
   174  	descriptor := descriptors[len(descriptors)-1]
   175  	if descriptor.StopPosition == 0 {
   176  		return nil, fmt.Errorf("recording length zero")
   177  	}
   178  
   179  	// Return the last recordingID
   180  	return descriptor, nil
   181  }