github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/processor/memquota/mem_quota_test.go (about)

     1  // Copyright 2022 PingCAP, 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  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package memquota
    15  
    16  import (
    17  	"context"
    18  	"sync"
    19  	"testing"
    20  
    21  	"github.com/pingcap/tiflow/cdc/model"
    22  	"github.com/pingcap/tiflow/pkg/spanz"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  func TestMemQuotaTryAcquire(t *testing.T) {
    27  	t.Parallel()
    28  
    29  	m := NewMemQuota(model.DefaultChangeFeedID("1"), 100, "")
    30  	defer m.Close()
    31  
    32  	require.True(t, m.TryAcquire(50))
    33  	require.True(t, m.TryAcquire(50))
    34  	require.False(t, m.TryAcquire(1))
    35  }
    36  
    37  func TestMemQuotaForceAcquire(t *testing.T) {
    38  	t.Parallel()
    39  
    40  	m := NewMemQuota(model.DefaultChangeFeedID("1"), 100, "")
    41  	defer m.Close()
    42  
    43  	require.True(t, m.TryAcquire(100))
    44  	require.False(t, m.TryAcquire(1))
    45  	m.ForceAcquire(1)
    46  	require.Equal(t, uint64(101), m.GetUsedBytes())
    47  }
    48  
    49  func TestMemQuotaBlockAcquire(t *testing.T) {
    50  	t.Parallel()
    51  
    52  	m := NewMemQuota(model.DefaultChangeFeedID("1"), 100, "")
    53  	defer m.Close()
    54  	err := m.BlockAcquire(100)
    55  	require.NoError(t, err)
    56  
    57  	span := spanz.TableIDToComparableSpan(1)
    58  	m.Record(span, model.NewResolvedTs(1), 50)
    59  	m.Record(span, model.NewResolvedTs(2), 50)
    60  
    61  	var wg sync.WaitGroup
    62  	wg.Add(1)
    63  	go func() {
    64  		defer wg.Done()
    65  		err := m.BlockAcquire(50)
    66  		require.NoError(t, err)
    67  	}()
    68  	wg.Add(1)
    69  	go func() {
    70  		defer wg.Done()
    71  		err := m.BlockAcquire(50)
    72  		require.NoError(t, err)
    73  	}()
    74  	m.Release(span, model.NewResolvedTs(1))
    75  	m.Release(span, model.NewResolvedTs(2))
    76  	wg.Wait()
    77  }
    78  
    79  func TestMemQuotaClose(t *testing.T) {
    80  	t.Parallel()
    81  
    82  	m := NewMemQuota(model.DefaultChangeFeedID("1"), 100, "")
    83  
    84  	err := m.BlockAcquire(100)
    85  	require.NoError(t, err)
    86  	span := spanz.TableIDToComparableSpan(1)
    87  	m.Record(span, model.NewResolvedTs(2), 100)
    88  
    89  	var wg sync.WaitGroup
    90  	wg.Add(1)
    91  	go func() {
    92  		defer wg.Done()
    93  		err := m.BlockAcquire(50)
    94  		if err != nil {
    95  			require.ErrorIs(t, err, context.Canceled)
    96  		}
    97  	}()
    98  	wg.Add(1)
    99  	go func() {
   100  		defer wg.Done()
   101  		err := m.BlockAcquire(50)
   102  		if err != nil {
   103  			require.ErrorIs(t, err, context.Canceled)
   104  		}
   105  	}()
   106  	wg.Add(1)
   107  	go func() {
   108  		defer wg.Done()
   109  		err := m.BlockAcquire(50)
   110  		if err != nil {
   111  			require.ErrorIs(t, err, context.Canceled)
   112  		}
   113  	}()
   114  
   115  	// Randomly release some memory.
   116  	wg.Add(1)
   117  	go func() {
   118  		defer wg.Done()
   119  		m.Release(span, model.NewResolvedTs(2))
   120  	}()
   121  	m.Close()
   122  	wg.Wait()
   123  }
   124  
   125  func TestMemQuotaRefund(t *testing.T) {
   126  	t.Parallel()
   127  
   128  	m := NewMemQuota(model.DefaultChangeFeedID("1"), 100, "")
   129  	defer m.Close()
   130  
   131  	require.True(t, m.TryAcquire(50))
   132  	require.True(t, m.TryAcquire(50))
   133  	m.Refund(50)
   134  	require.True(t, m.TryAcquire(1))
   135  	require.True(t, m.TryAcquire(49))
   136  
   137  	// Test notify the blocked acquire.
   138  	var wg sync.WaitGroup
   139  	wg.Add(1)
   140  	go func() {
   141  		defer wg.Done()
   142  		err := m.BlockAcquire(50)
   143  		require.NoError(t, err)
   144  	}()
   145  	m.Refund(50)
   146  	wg.Wait()
   147  }
   148  
   149  func TestMemQuotaHasAvailable(t *testing.T) {
   150  	t.Parallel()
   151  
   152  	m := NewMemQuota(model.DefaultChangeFeedID("1"), 100, "")
   153  	defer m.Close()
   154  
   155  	require.True(t, m.hasAvailable(100))
   156  	require.True(t, m.TryAcquire(100))
   157  	require.False(t, m.hasAvailable(1))
   158  }
   159  
   160  func TestMemQuotaRecordAndRelease(t *testing.T) {
   161  	t.Parallel()
   162  
   163  	m := NewMemQuota(model.DefaultChangeFeedID("1"), 300, "")
   164  	defer m.Close()
   165  	span := spanz.TableIDToComparableSpan(1)
   166  	m.AddTable(span)
   167  
   168  	require.True(t, m.TryAcquire(100))
   169  	m.Record(span, model.NewResolvedTs(100), 100)
   170  	require.True(t, m.TryAcquire(100))
   171  	m.Record(span, model.NewResolvedTs(200), 100)
   172  	require.True(t, m.TryAcquire(100))
   173  	m.Record(span, model.NewResolvedTs(300), 100)
   174  	require.False(t, m.TryAcquire(1))
   175  	require.False(t, m.hasAvailable(1))
   176  	// release the memory of resolvedTs 100
   177  	m.Release(span, model.NewResolvedTs(101))
   178  	require.True(t, m.hasAvailable(100))
   179  	// release the memory of resolvedTs 200
   180  	m.Release(span, model.NewResolvedTs(201))
   181  	require.True(t, m.hasAvailable(200))
   182  	// release the memory of resolvedTs 300
   183  	m.Release(span, model.NewResolvedTs(301))
   184  	require.True(t, m.hasAvailable(300))
   185  	// release the memory of resolvedTs 300 again
   186  	m.Release(span, model.NewResolvedTs(301))
   187  	require.True(t, m.hasAvailable(300))
   188  }
   189  
   190  func TestMemQuotaRecordAndReleaseWithBatchID(t *testing.T) {
   191  	t.Parallel()
   192  
   193  	m := NewMemQuota(model.DefaultChangeFeedID("1"), 300, "")
   194  	defer m.Close()
   195  	span := spanz.TableIDToComparableSpan(1)
   196  	m.AddTable(span)
   197  
   198  	require.True(t, m.TryAcquire(100))
   199  	resolvedTs := model.ResolvedTs{
   200  		Mode:    model.BatchResolvedMode,
   201  		Ts:      100,
   202  		BatchID: 1,
   203  	}
   204  	m.Record(span, resolvedTs, 100)
   205  	resolvedTs = model.ResolvedTs{
   206  		Mode:    model.BatchResolvedMode,
   207  		Ts:      100,
   208  		BatchID: 2,
   209  	}
   210  	require.True(t, m.TryAcquire(100))
   211  	m.Record(span, resolvedTs, 100)
   212  	resolvedTs = model.ResolvedTs{
   213  		Mode:    model.BatchResolvedMode,
   214  		Ts:      100,
   215  		BatchID: 3,
   216  	}
   217  	require.True(t, m.TryAcquire(100))
   218  	m.Record(span, resolvedTs, 100)
   219  	require.False(t, m.TryAcquire(1))
   220  	require.False(t, m.hasAvailable(1))
   221  
   222  	// release the memory of resolvedTs 100 batchID 2
   223  	resolvedTs = model.ResolvedTs{
   224  		Mode:    model.BatchResolvedMode,
   225  		Ts:      100,
   226  		BatchID: 2,
   227  	}
   228  	m.Release(span, resolvedTs)
   229  	require.True(t, m.hasAvailable(200))
   230  	// release the memory of resolvedTs 101
   231  	m.Release(span, model.NewResolvedTs(101))
   232  	require.True(t, m.hasAvailable(300))
   233  }
   234  
   235  func TestMemQuotaRecordAndClean(t *testing.T) {
   236  	t.Parallel()
   237  
   238  	m := NewMemQuota(model.DefaultChangeFeedID("1"), 300, "")
   239  	defer m.Close()
   240  	span := spanz.TableIDToComparableSpan(1)
   241  	m.AddTable(span)
   242  
   243  	require.True(t, m.TryAcquire(100))
   244  	m.Record(span, model.NewResolvedTs(100), 100)
   245  	require.True(t, m.TryAcquire(100))
   246  	m.Record(span, model.NewResolvedTs(200), 100)
   247  	require.True(t, m.TryAcquire(100))
   248  	m.Record(span, model.NewResolvedTs(300), 100)
   249  	require.False(t, m.TryAcquire(1))
   250  	require.False(t, m.hasAvailable(1))
   251  
   252  	// clean the all memory.
   253  	cleanedBytes := m.ClearTable(span)
   254  	require.Equal(t, uint64(300), cleanedBytes)
   255  	require.True(t, m.hasAvailable(100))
   256  
   257  	cleanedBytes = m.RemoveTable(span)
   258  	require.Equal(t, uint64(0), cleanedBytes)
   259  }