github.com/m3db/m3@v1.5.0/src/msg/producer/writer/message_writer_test.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package writer
    22  
    23  import (
    24  	"net"
    25  	"sync"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/fortytw2/leaktest"
    30  	"github.com/golang/mock/gomock"
    31  	"github.com/stretchr/testify/require"
    32  	"github.com/uber-go/tally"
    33  
    34  	"github.com/m3db/m3/src/msg/producer"
    35  	"github.com/m3db/m3/src/x/instrument"
    36  	"github.com/m3db/m3/src/x/retry"
    37  	xtest "github.com/m3db/m3/src/x/test"
    38  )
    39  
    40  func TestMessageWriterRandomIndex(t *testing.T) {
    41  	indexes := make([]int, 10)
    42  	reset := func() {
    43  		for i := range indexes {
    44  			indexes[i] = i
    45  		}
    46  	}
    47  
    48  	reset()
    49  	firstIdx := randIndex(indexes, len(indexes)-1)
    50  	for {
    51  		reset()
    52  		newIdx := randIndex(indexes, len(indexes)-1)
    53  		// Make sure the first index is random.
    54  		if firstIdx != newIdx {
    55  			break
    56  		}
    57  		time.Sleep(50 * time.Millisecond)
    58  	}
    59  
    60  	reset()
    61  	idx1 := randIndex(indexes, len(indexes)-1)
    62  	idx2 := randIndex(indexes, len(indexes)-2)
    63  	for {
    64  		reset()
    65  		newIdx1 := randIndex(indexes, len(indexes)-1)
    66  		newIdx2 := randIndex(indexes, len(indexes)-2)
    67  		// Make sure the order is random.
    68  		if idx2-idx1 != newIdx2-newIdx1 {
    69  			break
    70  		}
    71  		time.Sleep(50 * time.Millisecond)
    72  	}
    73  }
    74  
    75  func TestMessageWriterRandomFullIteration(t *testing.T) {
    76  	indexes := make([]int, 100)
    77  	var indexMap map[int]struct{}
    78  	reset := func() {
    79  		for i := range indexes {
    80  			indexes[i] = i
    81  		}
    82  		indexMap = make(map[int]struct{}, 100)
    83  	}
    84  
    85  	for n := 0; n < 1000; n++ {
    86  		reset()
    87  		for i := len(indexes) - 1; i >= 0; i-- {
    88  			idx := randIndex(indexes, i)
    89  			indexMap[idx] = struct{}{}
    90  		}
    91  		require.Equal(t, 100, len(indexMap))
    92  	}
    93  }
    94  
    95  func TestMessageWriterWithPooling(t *testing.T) {
    96  	defer leaktest.Check(t)()
    97  
    98  	lis, err := net.Listen("tcp", "127.0.0.1:0")
    99  	require.NoError(t, err)
   100  	defer lis.Close()
   101  
   102  	addr := lis.Addr().String()
   103  	opts := testOptions()
   104  
   105  	var wg sync.WaitGroup
   106  	defer wg.Wait()
   107  
   108  	wg.Add(1)
   109  	go func() {
   110  		testConsumeAndAckOnConnectionListener(t, lis, opts.EncoderOptions(), opts.DecoderOptions())
   111  		wg.Done()
   112  	}()
   113  
   114  	w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()).(*messageWriterImpl)
   115  	require.Equal(t, 200, int(w.ReplicatedShardID()))
   116  	w.Init()
   117  
   118  	a := newAckRouter(1)
   119  	a.Register(200, w)
   120  
   121  	cw := newConsumerWriter(addr, a, opts, testConsumerWriterMetrics())
   122  	cw.Init()
   123  	defer cw.Close()
   124  
   125  	w.AddConsumerWriter(cw)
   126  
   127  	ctrl := xtest.NewController(t)
   128  	defer ctrl.Finish()
   129  
   130  	mm1 := producer.NewMockMessage(ctrl)
   131  	mm1.EXPECT().Bytes().Return([]byte("foo")).Times(1)
   132  	mm1.EXPECT().Size().Return(3).Times(1)
   133  	mm1.EXPECT().Finalize(producer.Consumed)
   134  
   135  	w.Write(producer.NewRefCountedMessage(mm1, nil))
   136  
   137  	for {
   138  		w.RLock()
   139  		l := w.queue.Len()
   140  		w.RUnlock()
   141  		if l == 0 {
   142  			break
   143  		}
   144  		time.Sleep(100 * time.Millisecond)
   145  	}
   146  	require.Equal(t, 0, w.queue.Len())
   147  	w.RemoveConsumerWriter(addr)
   148  
   149  	mm2 := producer.NewMockMessage(ctrl)
   150  	mm2.EXPECT().Bytes().Return([]byte("bar")).Times(1)
   151  	mm2.EXPECT().Size().Return(3).Times(1)
   152  
   153  	w.Write(producer.NewRefCountedMessage(mm2, nil))
   154  	for {
   155  		if !isEmptyWithLock(w.acks) {
   156  			break
   157  		}
   158  		time.Sleep(100 * time.Millisecond)
   159  	}
   160  	require.Equal(t, 1, w.queue.Len())
   161  
   162  	mm2.EXPECT().Finalize(producer.Consumed)
   163  	w.Ack(metadata{metadataKey: metadataKey{shard: 200, id: 2}})
   164  	require.True(t, isEmptyWithLock(w.acks))
   165  	for {
   166  		w.RLock()
   167  		l := w.queue.Len()
   168  		w.RUnlock()
   169  		if l == 0 {
   170  			break
   171  		}
   172  		time.Sleep(100 * time.Millisecond)
   173  	}
   174  	w.Close()
   175  	w.Close()
   176  }
   177  
   178  func TestMessageWriterWithoutPooling(t *testing.T) {
   179  	defer leaktest.Check(t)()
   180  
   181  	lis, err := net.Listen("tcp", "127.0.0.1:0")
   182  	require.NoError(t, err)
   183  	defer lis.Close()
   184  
   185  	addr := lis.Addr().String()
   186  	opts := testOptions()
   187  
   188  	var wg sync.WaitGroup
   189  	defer wg.Wait()
   190  
   191  	wg.Add(1)
   192  	go func() {
   193  		testConsumeAndAckOnConnectionListener(t, lis, opts.EncoderOptions(), opts.DecoderOptions())
   194  		wg.Done()
   195  	}()
   196  
   197  	w := newMessageWriter(200, nil, opts, testMessageWriterMetrics()).(*messageWriterImpl)
   198  	require.Equal(t, 200, int(w.ReplicatedShardID()))
   199  	w.Init()
   200  
   201  	a := newAckRouter(1)
   202  	a.Register(200, w)
   203  
   204  	cw := newConsumerWriter(addr, a, opts, testConsumerWriterMetrics())
   205  	cw.Init()
   206  	defer cw.Close()
   207  
   208  	w.AddConsumerWriter(cw)
   209  
   210  	ctrl := xtest.NewController(t)
   211  	defer ctrl.Finish()
   212  
   213  	mm1 := producer.NewMockMessage(ctrl)
   214  	mm1.EXPECT().Bytes().Return([]byte("foo")).Times(1)
   215  	mm1.EXPECT().Size().Return(3).Times(1)
   216  	mm1.EXPECT().Finalize(producer.Consumed)
   217  
   218  	w.Write(producer.NewRefCountedMessage(mm1, nil))
   219  
   220  	for {
   221  		w.RLock()
   222  		l := w.queue.Len()
   223  		w.RUnlock()
   224  		if l == 0 {
   225  			break
   226  		}
   227  		time.Sleep(100 * time.Millisecond)
   228  	}
   229  	require.Equal(t, 0, w.queue.Len())
   230  	w.RemoveConsumerWriter(addr)
   231  
   232  	mm2 := producer.NewMockMessage(ctrl)
   233  	mm2.EXPECT().Bytes().Return([]byte("bar")).Times(1)
   234  	mm2.EXPECT().Size().Return(3).Times(1)
   235  
   236  	w.Write(producer.NewRefCountedMessage(mm2, nil))
   237  	for {
   238  		if !isEmptyWithLock(w.acks) {
   239  			break
   240  		}
   241  		time.Sleep(100 * time.Millisecond)
   242  	}
   243  	require.Equal(t, 1, w.queue.Len())
   244  
   245  	mm2.EXPECT().Finalize(producer.Consumed)
   246  	w.Ack(metadata{metadataKey: metadataKey{shard: 200, id: 2}})
   247  	require.True(t, isEmptyWithLock(w.acks))
   248  	for {
   249  		w.RLock()
   250  		l := w.queue.Len()
   251  		w.RUnlock()
   252  		if l == 0 {
   253  			break
   254  		}
   255  		time.Sleep(100 * time.Millisecond)
   256  	}
   257  	w.Close()
   258  	w.Close()
   259  }
   260  
   261  func TestMessageWriterRetryWithoutPooling(t *testing.T) {
   262  	defer leaktest.Check(t)()
   263  
   264  	lis, err := net.Listen("tcp", "127.0.0.1:0")
   265  	require.NoError(t, err)
   266  	defer lis.Close()
   267  
   268  	addr := lis.Addr().String()
   269  	opts := testOptions()
   270  	w := newMessageWriter(200, nil, opts, testMessageWriterMetrics()).(*messageWriterImpl)
   271  	w.Init()
   272  	defer w.Close()
   273  
   274  	a := newAckRouter(1)
   275  	a.Register(200, w)
   276  
   277  	ctrl := xtest.NewController(t)
   278  	defer ctrl.Finish()
   279  
   280  	mm := producer.NewMockMessage(ctrl)
   281  	mm.EXPECT().Bytes().Return([]byte("foo")).AnyTimes()
   282  	mm.EXPECT().Size().Return(3).Times(1)
   283  	mm.EXPECT().Finalize(producer.Consumed)
   284  
   285  	rm := producer.NewRefCountedMessage(mm, nil)
   286  	w.Write(rm)
   287  
   288  	w.AddConsumerWriter(newConsumerWriter("bad", a, opts, testConsumerWriterMetrics()))
   289  	require.Equal(t, 1, w.queue.Len())
   290  
   291  	for {
   292  		if !isEmptyWithLock(w.acks) {
   293  			break
   294  		}
   295  		time.Sleep(100 * time.Millisecond)
   296  	}
   297  
   298  	_, ok := w.acks.ackMap[metadataKey{shard: 200, id: 1}]
   299  	require.True(t, ok)
   300  
   301  	cw := newConsumerWriter(addr, a, opts, testConsumerWriterMetrics())
   302  	cw.Init()
   303  	defer cw.Close()
   304  
   305  	w.AddConsumerWriter(cw)
   306  	go func() {
   307  		testConsumeAndAckOnConnectionListener(t, lis, opts.EncoderOptions(), opts.DecoderOptions())
   308  	}()
   309  
   310  	for {
   311  		w.Lock()
   312  		l := w.queue.Len()
   313  		w.Unlock()
   314  		if l == 0 {
   315  			break
   316  		}
   317  		time.Sleep(100 * time.Millisecond)
   318  	}
   319  }
   320  
   321  func TestMessageWriterRetryWithPooling(t *testing.T) {
   322  	defer leaktest.Check(t)()
   323  
   324  	lis, err := net.Listen("tcp", "127.0.0.1:0")
   325  	require.NoError(t, err)
   326  	defer lis.Close()
   327  
   328  	addr := lis.Addr().String()
   329  	opts := testOptions()
   330  	w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()).(*messageWriterImpl)
   331  	w.Init()
   332  	defer w.Close()
   333  
   334  	a := newAckRouter(1)
   335  	a.Register(200, w)
   336  
   337  	ctrl := xtest.NewController(t)
   338  	defer ctrl.Finish()
   339  
   340  	mm := producer.NewMockMessage(ctrl)
   341  	mm.EXPECT().Bytes().Return([]byte("foo")).AnyTimes()
   342  	mm.EXPECT().Size().Return(3).Times(1)
   343  	mm.EXPECT().Finalize(producer.Consumed)
   344  
   345  	rm := producer.NewRefCountedMessage(mm, nil)
   346  	w.Write(rm)
   347  
   348  	w.AddConsumerWriter(newConsumerWriter("bad", a, opts, testConsumerWriterMetrics()))
   349  	require.Equal(t, 1, w.queue.Len())
   350  
   351  	for {
   352  		if !isEmptyWithLock(w.acks) {
   353  			break
   354  		}
   355  		time.Sleep(100 * time.Millisecond)
   356  	}
   357  
   358  	m1, ok := w.acks.ackMap[metadataKey{shard: 200, id: 1}]
   359  	require.True(t, ok)
   360  
   361  	cw := newConsumerWriter(addr, a, opts, testConsumerWriterMetrics())
   362  	cw.Init()
   363  	defer cw.Close()
   364  
   365  	w.AddConsumerWriter(cw)
   366  	go func() {
   367  		testConsumeAndAckOnConnectionListener(t, lis, opts.EncoderOptions(), opts.DecoderOptions())
   368  	}()
   369  
   370  	for {
   371  		w.Lock()
   372  		l := w.queue.Len()
   373  		w.Unlock()
   374  		if l == 0 {
   375  			break
   376  		}
   377  		time.Sleep(100 * time.Millisecond)
   378  	}
   379  
   380  	// A get will NOT allocate a new message because the old one has been returned to pool.
   381  	m := w.mPool.Get()
   382  	require.Equal(t, m1, m)
   383  	require.True(t, m.IsDroppedOrConsumed())
   384  }
   385  
   386  func TestMessageWriterCleanupDroppedMessage(t *testing.T) {
   387  	defer leaktest.Check(t)()
   388  
   389  	opts := testOptions()
   390  	w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics())
   391  
   392  	ctrl := xtest.NewController(t)
   393  	defer ctrl.Finish()
   394  
   395  	mm := producer.NewMockMessage(ctrl)
   396  
   397  	mm.EXPECT().Size().Return(3).Times(1)
   398  	rm := producer.NewRefCountedMessage(mm, nil)
   399  	mm.EXPECT().Finalize(producer.Dropped)
   400  	rm.Drop()
   401  	mm.EXPECT().Bytes().Return([]byte("foo"))
   402  	w.Write(rm)
   403  
   404  	// A get will allocate a new message because the old one has not been returned to pool yet.
   405  	m := w.(*messageWriterImpl).mPool.Get()
   406  	require.Nil(t, m.RefCountedMessage)
   407  
   408  	require.Equal(t, 1, w.(*messageWriterImpl).queue.Len())
   409  	w.Init()
   410  	defer w.Close()
   411  
   412  	for {
   413  		w.(*messageWriterImpl).Lock()
   414  		l := w.(*messageWriterImpl).queue.Len()
   415  		w.(*messageWriterImpl).Unlock()
   416  		if l != 1 {
   417  			break
   418  		}
   419  		time.Sleep(100 * time.Millisecond)
   420  	}
   421  	require.True(t, isEmptyWithLock(w.(*messageWriterImpl).acks))
   422  
   423  	// A get will NOT allocate a new message because the old one has been returned to pool.
   424  	m = w.(*messageWriterImpl).mPool.Get()
   425  	require.True(t, m.IsDroppedOrConsumed())
   426  }
   427  
   428  func TestMessageWriterCleanupAckedMessage(t *testing.T) {
   429  	defer leaktest.Check(t)()
   430  
   431  	opts := testOptions()
   432  	w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()).(*messageWriterImpl)
   433  	w.Init()
   434  	defer w.Close()
   435  
   436  	ctrl := xtest.NewController(t)
   437  	defer ctrl.Finish()
   438  
   439  	mm := producer.NewMockMessage(ctrl)
   440  	mm.EXPECT().Bytes().Return([]byte("foo"))
   441  	mm.EXPECT().Size().Return(3).Times(1)
   442  
   443  	rm := producer.NewRefCountedMessage(mm, nil)
   444  	// Another message write also holds this message.
   445  	rm.IncRef()
   446  
   447  	w.Write(rm)
   448  	for {
   449  		if !isEmptyWithLock(w.acks) {
   450  			break
   451  		}
   452  		time.Sleep(100 * time.Millisecond)
   453  	}
   454  	acks := w.acks
   455  	meta := metadata{
   456  		metadataKey: metadataKey{
   457  			id:    1,
   458  			shard: 200,
   459  		},
   460  	}
   461  	// The message will not be finalized because it's still being hold by another message writer.
   462  	acks.ack(meta)
   463  	require.True(t, isEmptyWithLock(w.acks))
   464  
   465  	// A get will allocate a new message because the old one has not been returned to pool yet.
   466  	m := w.mPool.Get()
   467  	require.Nil(t, m.RefCountedMessage)
   468  	require.Equal(t, 1, w.queue.Len())
   469  
   470  	for {
   471  		w.Lock()
   472  		l := w.queue.Len()
   473  		w.Unlock()
   474  		if l != 1 {
   475  			break
   476  		}
   477  		time.Sleep(100 * time.Millisecond)
   478  	}
   479  
   480  	// A get will NOT allocate a new message because the old one has been returned to pool.
   481  	m = w.mPool.Get()
   482  	require.Equal(t, meta, m.Metadata())
   483  }
   484  
   485  func TestMessageWriterCutoverCutoff(t *testing.T) {
   486  	ctrl := xtest.NewController(t)
   487  	defer ctrl.Finish()
   488  
   489  	w := newMessageWriter(200, testMessagePool(testOptions()), nil, testMessageWriterMetrics()).(*messageWriterImpl)
   490  	now := time.Now()
   491  	w.nowFn = func() time.Time { return now }
   492  	require.True(t, w.isValidWriteWithLock(now.UnixNano()))
   493  	require.True(t, w.isValidWriteWithLock(now.UnixNano()+150))
   494  	require.True(t, w.isValidWriteWithLock(now.UnixNano()+250))
   495  	require.True(t, w.isValidWriteWithLock(now.UnixNano()+50))
   496  
   497  	w.SetCutoffNanos(now.UnixNano() + 200)
   498  	w.SetCutoverNanos(now.UnixNano() + 100)
   499  	require.True(t, w.isValidWriteWithLock(now.UnixNano()+150))
   500  	require.False(t, w.isValidWriteWithLock(now.UnixNano()+250))
   501  	require.False(t, w.isValidWriteWithLock(now.UnixNano()+50))
   502  	require.Equal(t, 0, w.queue.Len())
   503  
   504  	mm := producer.NewMockMessage(ctrl)
   505  	mm.EXPECT().Size().Return(3)
   506  	w.Write(producer.NewRefCountedMessage(mm, nil))
   507  	require.Equal(t, 0, w.queue.Len())
   508  }
   509  
   510  func TestMessageWriterIgnoreCutoverCutoff(t *testing.T) {
   511  	ctrl := xtest.NewController(t)
   512  	defer ctrl.Finish()
   513  
   514  	opts := NewOptions().SetIgnoreCutoffCutover(true)
   515  
   516  	w := newMessageWriter(200, testMessagePool(testOptions()), opts, testMessageWriterMetrics()).(*messageWriterImpl)
   517  	now := time.Now()
   518  	w.nowFn = func() time.Time { return now }
   519  
   520  	w.SetCutoffNanos(now.UnixNano() + 200)
   521  	w.SetCutoverNanos(now.UnixNano() + 100)
   522  	require.True(t, w.isValidWriteWithLock(now.UnixNano()+150))
   523  	require.True(t, w.isValidWriteWithLock(now.UnixNano()+250))
   524  	require.True(t, w.isValidWriteWithLock(now.UnixNano()+50))
   525  	require.Equal(t, 0, w.queue.Len())
   526  
   527  	mm := producer.NewMockMessage(ctrl)
   528  	mm.EXPECT().Bytes().Return([]byte("foo"))
   529  	mm.EXPECT().Size().Return(3)
   530  	w.Write(producer.NewRefCountedMessage(mm, nil))
   531  	require.Equal(t, 1, w.queue.Len())
   532  }
   533  
   534  func TestMessageWriterKeepNewWritesInOrderInFrontOfTheQueue(t *testing.T) {
   535  	ctrl := xtest.NewController(t)
   536  	defer ctrl.Finish()
   537  
   538  	opts := testOptions().SetMessageRetryNanosFn(
   539  		NextRetryNanosFn(retry.NewOptions().SetInitialBackoff(2 * time.Nanosecond).SetMaxBackoff(5 * time.Nanosecond)),
   540  	)
   541  	w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()).(*messageWriterImpl)
   542  
   543  	now := time.Now()
   544  	w.nowFn = func() time.Time { return now }
   545  
   546  	mm1 := producer.NewMockMessage(ctrl)
   547  	mm1.EXPECT().Size().Return(3)
   548  	rm1 := producer.NewRefCountedMessage(mm1, nil)
   549  	mm1.EXPECT().Bytes().Return([]byte("1")).AnyTimes()
   550  	w.Write(rm1)
   551  	validateMessages(t, []*producer.RefCountedMessage{rm1}, w)
   552  	mm2 := producer.NewMockMessage(ctrl)
   553  	mm2.EXPECT().Size().Return(3)
   554  	rm2 := producer.NewRefCountedMessage(mm2, nil)
   555  	mm2.EXPECT().Bytes().Return([]byte("2")).AnyTimes()
   556  	w.Write(rm2)
   557  	validateMessages(t, []*producer.RefCountedMessage{rm1, rm2}, w)
   558  	w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano(), 2, true, &scanBatchMetrics{})
   559  
   560  	w.lastNewWrite = nil
   561  	mm3 := producer.NewMockMessage(ctrl)
   562  	mm3.EXPECT().Size().Return(3)
   563  	rm3 := producer.NewRefCountedMessage(mm3, nil)
   564  	mm3.EXPECT().Bytes().Return([]byte("3")).AnyTimes()
   565  	w.Write(rm3)
   566  	validateMessages(t, []*producer.RefCountedMessage{rm3, rm1, rm2}, w)
   567  
   568  	mm4 := producer.NewMockMessage(ctrl)
   569  	mm4.EXPECT().Size().Return(3)
   570  	rm4 := producer.NewRefCountedMessage(mm4, nil)
   571  	mm4.EXPECT().Bytes().Return([]byte("4")).AnyTimes()
   572  	w.Write(rm4)
   573  
   574  	validateMessages(t, []*producer.RefCountedMessage{rm3, rm4, rm1, rm2}, w)
   575  }
   576  
   577  func TestMessageWriterRetryIterateBatchFullScan(t *testing.T) {
   578  	ctrl := xtest.NewController(t)
   579  	defer ctrl.Finish()
   580  
   581  	retryBatchSize := 2
   582  	opts := testOptions().SetMessageQueueScanBatchSize(retryBatchSize).SetMessageRetryNanosFn(
   583  		NextRetryNanosFn(retry.NewOptions().SetInitialBackoff(2 * time.Nanosecond).SetMaxBackoff(5 * time.Nanosecond)),
   584  	)
   585  	w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()).(*messageWriterImpl)
   586  
   587  	now := time.Now()
   588  	w.nowFn = func() time.Time { return now }
   589  
   590  	mm1 := producer.NewMockMessage(ctrl)
   591  	mm1.EXPECT().Size().Return(3)
   592  	rm1 := producer.NewRefCountedMessage(mm1, nil)
   593  	mm1.EXPECT().Bytes().Return([]byte("1")).AnyTimes()
   594  	w.Write(rm1)
   595  
   596  	mm2 := producer.NewMockMessage(ctrl)
   597  	mm2.EXPECT().Size().Return(3)
   598  	rm2 := producer.NewRefCountedMessage(mm2, nil)
   599  	mm2.EXPECT().Bytes().Return([]byte("2")).AnyTimes()
   600  	w.Write(rm2)
   601  
   602  	mm3 := producer.NewMockMessage(ctrl)
   603  	mm3.EXPECT().Size().Return(3)
   604  	rm3 := producer.NewRefCountedMessage(mm3, nil)
   605  	mm3.EXPECT().Bytes().Return([]byte("3")).AnyTimes()
   606  	w.Write(rm3)
   607  
   608  	mm4 := producer.NewMockMessage(ctrl)
   609  	mm4.EXPECT().Size().Return(3)
   610  	rm4 := producer.NewRefCountedMessage(mm4, nil)
   611  	mm4.EXPECT().Bytes().Return([]byte("4")).AnyTimes()
   612  	w.Write(rm4)
   613  
   614  	validateMessages(t, []*producer.RefCountedMessage{rm1, rm2, rm3, rm4}, w)
   615  	mm1.EXPECT().Finalize(gomock.Eq(producer.Dropped))
   616  	rm1.Drop()
   617  	require.Equal(t, 4, w.queue.Len())
   618  	e, toBeRetried := w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano(), retryBatchSize, true, &scanBatchMetrics{})
   619  	require.Equal(t, 1, len(toBeRetried))
   620  	require.Equal(t, 3, w.queue.Len())
   621  
   622  	// Make sure it stopped at rm3.
   623  	require.Equal(t, rm3, e.Value.(*message).RefCountedMessage)
   624  
   625  	require.Equal(t, 3, w.queue.Len())
   626  	e, toBeRetried = w.scanBatchWithLock(e, w.nowFn().UnixNano(), retryBatchSize, true, &scanBatchMetrics{})
   627  	require.Nil(t, e)
   628  	require.Equal(t, 2, len(toBeRetried))
   629  	require.Equal(t, 3, w.queue.Len())
   630  
   631  	e, toBeRetried = w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano(), retryBatchSize, true, &scanBatchMetrics{})
   632  	// Make sure it stopped at rm4.
   633  	require.Equal(t, rm4, e.Value.(*message).RefCountedMessage)
   634  	require.Equal(t, 0, len(toBeRetried))
   635  
   636  	e, toBeRetried = w.scanBatchWithLock(e, w.nowFn().UnixNano(), retryBatchSize, true, &scanBatchMetrics{})
   637  	require.Nil(t, e)
   638  	require.Equal(t, 0, len(toBeRetried))
   639  }
   640  
   641  //nolint:lll
   642  func TestMessageWriterRetryIterateBatchFullScanWithMessageTTL(t *testing.T) {
   643  	ctrl := xtest.NewController(t)
   644  	defer ctrl.Finish()
   645  
   646  	retryBatchSize := 2
   647  	opts := testOptions().SetMessageQueueScanBatchSize(retryBatchSize).SetMessageRetryNanosFn(
   648  		NextRetryNanosFn(retry.NewOptions().SetInitialBackoff(2 * time.Nanosecond).SetMaxBackoff(5 * time.Nanosecond)),
   649  	)
   650  	w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()).(*messageWriterImpl)
   651  
   652  	now := time.Now()
   653  	w.nowFn = func() time.Time { return now }
   654  
   655  	mm1 := producer.NewMockMessage(ctrl)
   656  	mm1.EXPECT().Size().Return(3)
   657  	rm1 := producer.NewRefCountedMessage(mm1, nil)
   658  	mm1.EXPECT().Bytes().Return([]byte("1")).AnyTimes()
   659  	w.Write(rm1)
   660  
   661  	mm2 := producer.NewMockMessage(ctrl)
   662  	mm2.EXPECT().Size().Return(3)
   663  	rm2 := producer.NewRefCountedMessage(mm2, nil)
   664  	mm2.EXPECT().Bytes().Return([]byte("2")).AnyTimes()
   665  	w.Write(rm2)
   666  
   667  	mm3 := producer.NewMockMessage(ctrl)
   668  	mm3.EXPECT().Size().Return(3)
   669  	rm3 := producer.NewRefCountedMessage(mm3, nil)
   670  	mm3.EXPECT().Bytes().Return([]byte("3")).AnyTimes()
   671  	w.Write(rm3)
   672  
   673  	mm4 := producer.NewMockMessage(ctrl)
   674  	mm4.EXPECT().Size().Return(3)
   675  	rm4 := producer.NewRefCountedMessage(mm4, nil)
   676  	mm4.EXPECT().Bytes().Return([]byte("4")).AnyTimes()
   677  	w.Write(rm4)
   678  
   679  	mm1.EXPECT().Finalize(gomock.Eq(producer.Dropped))
   680  	rm1.Drop()
   681  	require.Equal(t, 4, w.queue.Len())
   682  	e, toBeRetried := w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano(), retryBatchSize, true, &scanBatchMetrics{})
   683  	require.Equal(t, 1, len(toBeRetried))
   684  	require.Equal(t, 3, w.queue.Len())
   685  
   686  	require.Equal(t, rm2, e.Value.(*message).RefCountedMessage)
   687  
   688  	w.SetMessageTTLNanos(int64(time.Minute))
   689  	mm4.EXPECT().Finalize(gomock.Eq(producer.Consumed))
   690  	mm3.EXPECT().Finalize(gomock.Eq(producer.Consumed))
   691  	e, toBeRetried = w.scanBatchWithLock(e, w.nowFn().UnixNano()+int64(time.Hour), retryBatchSize, true, &scanBatchMetrics{})
   692  	require.Equal(t, 0, len(toBeRetried))
   693  	require.Equal(t, 1, w.queue.Len())
   694  	require.Nil(t, e)
   695  
   696  	mm2.EXPECT().Finalize(gomock.Eq(producer.Consumed))
   697  	e, toBeRetried = w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano()+int64(time.Hour), retryBatchSize, true, &scanBatchMetrics{})
   698  	require.Equal(t, 0, len(toBeRetried))
   699  	require.Equal(t, 0, w.queue.Len())
   700  	require.Nil(t, e)
   701  }
   702  
   703  //nolint:lll
   704  func TestMessageWriterRetryIterateBatchNotFullScan(t *testing.T) {
   705  	ctrl := xtest.NewController(t)
   706  	defer ctrl.Finish()
   707  
   708  	retryBatchSize := 100
   709  	opts := testOptions().SetMessageQueueScanBatchSize(retryBatchSize).SetMessageRetryNanosFn(
   710  		NextRetryNanosFn(retry.NewOptions().SetInitialBackoff(2 * time.Nanosecond).SetMaxBackoff(5 * time.Nanosecond)),
   711  	)
   712  	w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()).(*messageWriterImpl)
   713  
   714  	now := time.Now()
   715  	w.nowFn = func() time.Time { return now }
   716  
   717  	mm1 := producer.NewMockMessage(ctrl)
   718  	mm1.EXPECT().Size().Return(1)
   719  	rm1 := producer.NewRefCountedMessage(mm1, nil)
   720  	mm1.EXPECT().Bytes().Return([]byte("1")).AnyTimes()
   721  	w.Write(rm1)
   722  
   723  	mm2 := producer.NewMockMessage(ctrl)
   724  	mm2.EXPECT().Size().Return(1)
   725  	rm2 := producer.NewRefCountedMessage(mm2, nil)
   726  	mm2.EXPECT().Bytes().Return([]byte("2")).AnyTimes()
   727  	w.Write(rm2)
   728  
   729  	mm3 := producer.NewMockMessage(ctrl)
   730  	mm3.EXPECT().Size().Return(1)
   731  	rm3 := producer.NewRefCountedMessage(mm3, nil)
   732  	mm3.EXPECT().Bytes().Return([]byte("3")).AnyTimes()
   733  	w.Write(rm3)
   734  
   735  	mm4 := producer.NewMockMessage(ctrl)
   736  	mm4.EXPECT().Size().Return(1)
   737  	rm4 := producer.NewRefCountedMessage(mm4, nil)
   738  	mm4.EXPECT().Bytes().Return([]byte("4")).AnyTimes()
   739  	w.Write(rm4)
   740  
   741  	mm1.EXPECT().Finalize(gomock.Eq(producer.Dropped))
   742  	rm1.Drop()
   743  	require.Equal(t, 4, w.queue.Len())
   744  	e, toBeRetried := w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano(), retryBatchSize, false, &scanBatchMetrics{})
   745  	require.Equal(t, 3, len(toBeRetried))
   746  	require.Equal(t, 3, w.queue.Len())
   747  	require.Nil(t, e)
   748  	validateMessages(t, []*producer.RefCountedMessage{rm2, rm3, rm4}, w)
   749  	// Although mm4 is dropped, it will not be removed from the queue because
   750  	// it was not checked.
   751  	mm4.EXPECT().Finalize(gomock.Eq(producer.Dropped))
   752  	rm4.Drop()
   753  	require.Equal(t, 3, w.queue.Len())
   754  	e, toBeRetried = w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano(), retryBatchSize, false, &scanBatchMetrics{})
   755  	require.Equal(t, rm2, e.Value.(*message).RefCountedMessage)
   756  	require.Equal(t, 0, len(toBeRetried))
   757  	require.Equal(t, 3, w.queue.Len())
   758  	require.Equal(t, rm2, e.Value.(*message).RefCountedMessage)
   759  	validateMessages(t, []*producer.RefCountedMessage{rm2, rm3, rm4}, w)
   760  	w.lastNewWrite = nil
   761  
   762  	mm5 := producer.NewMockMessage(ctrl)
   763  	mm5.EXPECT().Size().Return(1)
   764  	rm5 := producer.NewRefCountedMessage(mm5, nil)
   765  	mm5.EXPECT().Bytes().Return([]byte("5")).AnyTimes()
   766  	w.Write(rm5)
   767  	validateMessages(t, []*producer.RefCountedMessage{rm5, rm2, rm3, rm4}, w)
   768  
   769  	require.Equal(t, 4, w.queue.Len())
   770  	e, toBeRetried = w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano(), retryBatchSize, false, &scanBatchMetrics{})
   771  	require.Equal(t, rm2, e.Value.(*message).RefCountedMessage)
   772  	require.Equal(t, 1, len(toBeRetried))
   773  	require.Equal(t, rm5, toBeRetried[0].RefCountedMessage)
   774  	require.Equal(t, 4, w.queue.Len())
   775  }
   776  
   777  func TestNextRetryAfterNanos(t *testing.T) {
   778  	backoffDuration := time.Minute
   779  	opts := testOptions().
   780  		SetMessageRetryNanosFn(
   781  			NextRetryNanosFn(
   782  				retry.NewOptions().
   783  					SetInitialBackoff(backoffDuration).
   784  					SetMaxBackoff(2 * backoffDuration).
   785  					SetJitter(true),
   786  			),
   787  		)
   788  	w := newMessageWriter(200, nil, opts, testMessageWriterMetrics()).(*messageWriterImpl)
   789  
   790  	nowNanos := time.Now().UnixNano()
   791  	m := newMessage()
   792  	m.IncWriteTimes()
   793  	retryAtNanos := w.nextRetryAfterNanos(m.WriteTimes()) + nowNanos
   794  	require.True(t, retryAtNanos > nowNanos)
   795  	require.True(t, retryAtNanos < nowNanos+int64(backoffDuration))
   796  
   797  	m.IncWriteTimes()
   798  	retryAtNanos = w.nextRetryAfterNanos(m.WriteTimes()) + nowNanos
   799  	require.True(t, retryAtNanos >= nowNanos+int64(backoffDuration))
   800  	require.True(t, retryAtNanos < nowNanos+2*int64(backoffDuration))
   801  
   802  	m.IncWriteTimes()
   803  	retryAtNanos = w.nextRetryAfterNanos(m.WriteTimes()) + nowNanos
   804  	require.True(t, retryAtNanos == nowNanos+2*int64(backoffDuration))
   805  }
   806  
   807  func TestStaticRetryAfterNanos(t *testing.T) {
   808  	fn, err := StaticRetryNanosFn([]time.Duration{time.Minute, 10 * time.Second, 5 * time.Second})
   809  	require.NoError(t, err)
   810  
   811  	opts := testOptions().SetMessageRetryNanosFn(fn)
   812  	w := newMessageWriter(200, nil, opts, testMessageWriterMetrics()).(*messageWriterImpl)
   813  
   814  	m := newMessage()
   815  	m.IncWriteTimes()
   816  	retryAtNanos := w.nextRetryAfterNanos(m.WriteTimes())
   817  	require.Equal(t, int64(time.Minute), retryAtNanos)
   818  
   819  	m.IncWriteTimes()
   820  	retryAtNanos = w.nextRetryAfterNanos(m.WriteTimes())
   821  	require.Equal(t, int64(10*time.Second), retryAtNanos)
   822  
   823  	m.IncWriteTimes()
   824  	retryAtNanos = w.nextRetryAfterNanos(m.WriteTimes())
   825  	require.Equal(t, int64(5*time.Second), retryAtNanos)
   826  
   827  	m.IncWriteTimes()
   828  	retryAtNanos = w.nextRetryAfterNanos(m.WriteTimes())
   829  	require.Equal(t, int64(5*time.Second), retryAtNanos)
   830  }
   831  
   832  func TestExpectedProcessedAt(t *testing.T) {
   833  	m := newMessage()
   834  	m.initNanos = 100
   835  	m.SetRetryAtNanos(200)
   836  	require.Equal(t, int64(100), m.ExpectedProcessAtNanos())
   837  	m.SetRetryAtNanos(300)
   838  	require.Equal(t, int64(200), m.ExpectedProcessAtNanos())
   839  }
   840  
   841  func TestMessageWriterCloseCleanupAllMessages(t *testing.T) {
   842  	defer leaktest.Check(t)()
   843  
   844  	opts := testOptions()
   845  	w := newMessageWriter(200, nil, opts, testMessageWriterMetrics()).(*messageWriterImpl)
   846  
   847  	ctrl := xtest.NewController(t)
   848  	defer ctrl.Finish()
   849  
   850  	mm := producer.NewMockMessage(ctrl)
   851  	mm.EXPECT().Size().Return(3)
   852  
   853  	rm := producer.NewRefCountedMessage(mm, nil)
   854  	mm.EXPECT().Finalize(producer.Consumed)
   855  	mm.EXPECT().Bytes().Return([]byte("foo"))
   856  	w.Write(rm)
   857  	require.False(t, isEmptyWithLock(w.acks))
   858  	require.Equal(t, 1, w.queue.Len())
   859  	w.Init()
   860  	w.Close()
   861  	require.Equal(t, 0, w.queue.Len())
   862  	require.True(t, isEmptyWithLock(w.acks))
   863  }
   864  
   865  func TestMessageWriterQueueFullScanOnWriteErrors(t *testing.T) {
   866  	ctrl := xtest.NewController(t)
   867  	defer ctrl.Finish()
   868  
   869  	opts := testOptions().SetMessageQueueScanBatchSize(1)
   870  	scope := tally.NewTestScope("", nil)
   871  	metrics := testMessageWriterMetricsWithScope(scope).withConsumer("c1")
   872  	w := newMessageWriter(200, nil, opts, metrics).(*messageWriterImpl)
   873  	w.AddConsumerWriter(newConsumerWriter("bad", nil, opts, testConsumerWriterMetrics()))
   874  
   875  	mm1 := producer.NewMockMessage(ctrl)
   876  	mm1.EXPECT().Size().Return(3)
   877  	mm1.EXPECT().Bytes().Return([]byte("foo"))
   878  	rm1 := producer.NewRefCountedMessage(mm1, nil)
   879  	w.Write(rm1)
   880  	require.Equal(t, 1, w.queue.Len())
   881  
   882  	mm2 := producer.NewMockMessage(ctrl)
   883  	mm2.EXPECT().Size().Return(3)
   884  	mm2.EXPECT().Bytes().Return([]byte("foo"))
   885  	rm2 := producer.NewRefCountedMessage(mm2, nil)
   886  	w.Write(rm2)
   887  	require.Equal(t, 2, w.queue.Len())
   888  
   889  	mm1.EXPECT().Finalize(producer.Dropped)
   890  	rm1.Drop()
   891  	w.scanMessageQueue()
   892  	require.Equal(t, 1, w.queue.Len())
   893  
   894  	snapshot := scope.Snapshot()
   895  	counters := snapshot.Counters()
   896  	require.Equal(t, int64(1), counters["message-processed+consumer=c1,result=write"].Value())
   897  	require.Equal(t, int64(1), counters["message-processed+consumer=c1,result=drop"].Value())
   898  }
   899  
   900  func TestMessageWriter_WithoutConsumerScope(t *testing.T) {
   901  	ctrl := xtest.NewController(t)
   902  	defer ctrl.Finish()
   903  
   904  	opts := testOptions().SetMessageQueueScanBatchSize(1)
   905  	scope := tally.NewTestScope("", nil)
   906  	metrics := newMessageWriterMetrics(scope, instrument.TimerOptions{}, true)
   907  	w := newMessageWriter(200, nil, opts, metrics).(*messageWriterImpl)
   908  	w.AddConsumerWriter(newConsumerWriter("bad", nil, opts, testConsumerWriterMetrics()))
   909  
   910  	snapshot := scope.Snapshot()
   911  	counters := snapshot.Counters()
   912  	require.Nil(t, counters["message-processed+consumer=c1,result=write"])
   913  	require.NotNil(t, counters["message-processed+result=write"])
   914  }
   915  
   916  func isEmptyWithLock(h *acks) bool {
   917  	h.Lock()
   918  	defer h.Unlock()
   919  	return len(h.ackMap) == 0
   920  }
   921  
   922  func testMessagePool(opts Options) messagePool {
   923  	p := newMessagePool(opts.MessagePoolOptions())
   924  	p.Init()
   925  	return p
   926  }
   927  
   928  func testMessageWriterMetrics() messageWriterMetrics {
   929  	return newMessageWriterMetrics(tally.NoopScope, instrument.TimerOptions{}, false)
   930  }
   931  
   932  func testMessageWriterMetricsWithScope(scope tally.TestScope) messageWriterMetrics {
   933  	return newMessageWriterMetrics(scope, instrument.TimerOptions{}, false)
   934  }
   935  
   936  func validateMessages(t *testing.T, msgs []*producer.RefCountedMessage, w *messageWriterImpl) {
   937  	w.RLock()
   938  	idx := 0
   939  	for e := w.queue.Front(); e != nil; e = e.Next() {
   940  		require.Equal(t, msgs[idx].Bytes(), e.Value.(*message).RefCountedMessage.Bytes())
   941  		idx++
   942  	}
   943  	w.RUnlock()
   944  	require.Equal(t, idx, len(msgs))
   945  }