github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/soliton/memory/tracker_test.go (about)

     1  // Copyright 2020 WHTCORPS INC, 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 memory
    15  
    16  import (
    17  	"math/rand"
    18  	"os"
    19  	"sync"
    20  	"testing"
    21  
    22  	"github.com/cznic/mathutil"
    23  	. "github.com/whtcorpsinc/check"
    24  	"github.com/whtcorpsinc/BerolinaSQL/terror"
    25  	"github.com/whtcorpsinc/milevadb/errno"
    26  	"github.com/whtcorpsinc/milevadb/soliton/logutil"
    27  	"github.com/whtcorpsinc/milevadb/soliton/testleak"
    28  )
    29  
    30  func TestT(t *testing.T) {
    31  	CustomVerboseFlag = true
    32  	logLevel := os.Getenv("log_level")
    33  	logutil.InitLogger(logutil.NewLogConfig(logLevel, logutil.DefaultLogFormat, "", logutil.EmptyFileLogConfig, false))
    34  	TestingT(t)
    35  }
    36  
    37  var _ = Suite(&testSuite{})
    38  
    39  type testSuite struct{}
    40  
    41  func (s *testSuite) SetUpSuite(c *C)    {}
    42  func (s *testSuite) TearDownSuite(c *C) {}
    43  func (s *testSuite) SetUpTest(c *C)     { testleak.BeforeTest() }
    44  func (s *testSuite) TearDownTest(c *C)  { testleak.AfterTest(c)() }
    45  
    46  func (s *testSuite) TestSetLabel(c *C) {
    47  	tracker := NewTracker(1, -1)
    48  	c.Assert(tracker.label, Equals, 1)
    49  	c.Assert(tracker.BytesConsumed(), Equals, int64(0))
    50  	c.Assert(tracker.bytesLimit, Equals, int64(-1))
    51  	c.Assert(tracker.getParent(), IsNil)
    52  	c.Assert(len(tracker.mu.children), Equals, 0)
    53  	tracker.SetLabel(2)
    54  	c.Assert(tracker.label, Equals, 2)
    55  	c.Assert(tracker.BytesConsumed(), Equals, int64(0))
    56  	c.Assert(tracker.bytesLimit, Equals, int64(-1))
    57  	c.Assert(tracker.getParent(), IsNil)
    58  	c.Assert(len(tracker.mu.children), Equals, 0)
    59  }
    60  
    61  func (s *testSuite) TestConsume(c *C) {
    62  	tracker := NewTracker(1, -1)
    63  	c.Assert(tracker.BytesConsumed(), Equals, int64(0))
    64  
    65  	tracker.Consume(100)
    66  	c.Assert(tracker.BytesConsumed(), Equals, int64(100))
    67  
    68  	waitGroup := sync.WaitGroup{}
    69  	waitGroup.Add(10)
    70  	for i := 0; i < 10; i++ {
    71  		go func() {
    72  			defer waitGroup.Done()
    73  			tracker.Consume(10)
    74  		}()
    75  	}
    76  	waitGroup.Add(10)
    77  	for i := 0; i < 10; i++ {
    78  		go func() {
    79  			defer waitGroup.Done()
    80  			tracker.Consume(-10)
    81  		}()
    82  	}
    83  
    84  	waitGroup.Wait()
    85  	c.Assert(tracker.BytesConsumed(), Equals, int64(100))
    86  }
    87  
    88  func (s *testSuite) TestOOMCausetAction(c *C) {
    89  	tracker := NewTracker(1, 100)
    90  	// make sure no panic here.
    91  	tracker.Consume(10000)
    92  
    93  	tracker = NewTracker(1, 100)
    94  	action := &mockCausetAction{}
    95  	tracker.SetSuperCowOrNoCausetOnExceed(action)
    96  
    97  	c.Assert(action.called, IsFalse)
    98  	tracker.Consume(10000)
    99  	c.Assert(action.called, IsTrue)
   100  
   101  	// test fallback
   102  	action1 := &mockCausetAction{}
   103  	action2 := &mockCausetAction{}
   104  	tracker.SetSuperCowOrNoCausetOnExceed(action1)
   105  	tracker.FallbackOldAndSetNewCausetAction(action2)
   106  	c.Assert(action1.called, IsFalse)
   107  	c.Assert(action2.called, IsFalse)
   108  	tracker.Consume(10000)
   109  	c.Assert(action1.called, IsFalse)
   110  	c.Assert(action2.called, IsTrue)
   111  	tracker.Consume(10000)
   112  	c.Assert(action1.called, IsTrue)
   113  	c.Assert(action2.called, IsTrue)
   114  }
   115  
   116  type mockCausetAction struct {
   117  	called   bool
   118  	fallback SuperCowOrNoCausetOnExceed
   119  }
   120  
   121  func (a *mockCausetAction) SetLogHook(hook func(uint64)) {
   122  }
   123  
   124  func (a *mockCausetAction) CausetAction(t *Tracker) {
   125  	if a.called && a.fallback != nil {
   126  		a.fallback.CausetAction(t)
   127  		return
   128  	}
   129  	a.called = true
   130  }
   131  
   132  func (a *mockCausetAction) SetFallback(fallback SuperCowOrNoCausetOnExceed) {
   133  	a.fallback = fallback
   134  }
   135  
   136  func (s *testSuite) TestAttachTo(c *C) {
   137  	oldParent := NewTracker(1, -1)
   138  	newParent := NewTracker(2, -1)
   139  	child := NewTracker(3, -1)
   140  	child.Consume(100)
   141  	child.AttachTo(oldParent)
   142  	c.Assert(child.BytesConsumed(), Equals, int64(100))
   143  	c.Assert(oldParent.BytesConsumed(), Equals, int64(100))
   144  	c.Assert(child.getParent(), DeepEquals, oldParent)
   145  	c.Assert(len(oldParent.mu.children), Equals, 1)
   146  	c.Assert(oldParent.mu.children[0], DeepEquals, child)
   147  
   148  	child.AttachTo(newParent)
   149  	c.Assert(child.BytesConsumed(), Equals, int64(100))
   150  	c.Assert(oldParent.BytesConsumed(), Equals, int64(0))
   151  	c.Assert(newParent.BytesConsumed(), Equals, int64(100))
   152  	c.Assert(child.getParent(), DeepEquals, newParent)
   153  	c.Assert(len(newParent.mu.children), Equals, 1)
   154  	c.Assert(newParent.mu.children[0], DeepEquals, child)
   155  	c.Assert(len(oldParent.mu.children), Equals, 0)
   156  }
   157  
   158  func (s *testSuite) TestDetach(c *C) {
   159  	parent := NewTracker(1, -1)
   160  	child := NewTracker(2, -1)
   161  	child.Consume(100)
   162  	child.AttachTo(parent)
   163  	c.Assert(child.BytesConsumed(), Equals, int64(100))
   164  	c.Assert(parent.BytesConsumed(), Equals, int64(100))
   165  	c.Assert(len(parent.mu.children), Equals, 1)
   166  	c.Assert(parent.mu.children[0], DeepEquals, child)
   167  
   168  	child.Detach()
   169  	c.Assert(child.BytesConsumed(), Equals, int64(100))
   170  	c.Assert(parent.BytesConsumed(), Equals, int64(0))
   171  	c.Assert(len(parent.mu.children), Equals, 0)
   172  	c.Assert(child.getParent(), IsNil)
   173  }
   174  
   175  func (s *testSuite) TestReplaceChild(c *C) {
   176  	oldChild := NewTracker(1, -1)
   177  	oldChild.Consume(100)
   178  	newChild := NewTracker(2, -1)
   179  	newChild.Consume(500)
   180  	parent := NewTracker(3, -1)
   181  
   182  	oldChild.AttachTo(parent)
   183  	c.Assert(parent.BytesConsumed(), Equals, int64(100))
   184  
   185  	parent.ReplaceChild(oldChild, newChild)
   186  	c.Assert(parent.BytesConsumed(), Equals, int64(500))
   187  	c.Assert(len(parent.mu.children), Equals, 1)
   188  	c.Assert(parent.mu.children[0], DeepEquals, newChild)
   189  	c.Assert(newChild.getParent(), DeepEquals, parent)
   190  	c.Assert(oldChild.getParent(), IsNil)
   191  
   192  	parent.ReplaceChild(oldChild, nil)
   193  	c.Assert(parent.BytesConsumed(), Equals, int64(500))
   194  	c.Assert(len(parent.mu.children), Equals, 1)
   195  	c.Assert(parent.mu.children[0], DeepEquals, newChild)
   196  	c.Assert(newChild.getParent(), DeepEquals, parent)
   197  	c.Assert(oldChild.getParent(), IsNil)
   198  
   199  	parent.ReplaceChild(newChild, nil)
   200  	c.Assert(parent.BytesConsumed(), Equals, int64(0))
   201  	c.Assert(len(parent.mu.children), Equals, 0)
   202  	c.Assert(newChild.getParent(), IsNil)
   203  	c.Assert(oldChild.getParent(), IsNil)
   204  
   205  	node1 := NewTracker(1, -1)
   206  	node2 := NewTracker(2, -1)
   207  	node3 := NewTracker(3, -1)
   208  	node2.AttachTo(node1)
   209  	node3.AttachTo(node2)
   210  	node3.Consume(100)
   211  	c.Assert(node1.BytesConsumed(), Equals, int64(100))
   212  	node2.ReplaceChild(node3, nil)
   213  	c.Assert(node2.BytesConsumed(), Equals, int64(0))
   214  	c.Assert(node1.BytesConsumed(), Equals, int64(0))
   215  }
   216  
   217  func (s *testSuite) TestToString(c *C) {
   218  	parent := NewTracker(1, -1)
   219  	child1 := NewTracker(2, 1000)
   220  	child2 := NewTracker(3, -1)
   221  	child3 := NewTracker(4, -1)
   222  	child4 := NewTracker(5, -1)
   223  
   224  	child1.AttachTo(parent)
   225  	child2.AttachTo(parent)
   226  	child3.AttachTo(parent)
   227  	child4.AttachTo(parent)
   228  
   229  	child1.Consume(100)
   230  	child2.Consume(2 * 1024)
   231  	child3.Consume(3 * 1024 * 1024)
   232  	child4.Consume(4 * 1024 * 1024 * 1024)
   233  
   234  	c.Assert(parent.String(), Equals, `
   235  "1"{
   236    "consumed": 4.00293168798089 GB
   237    "2"{
   238      "quota": 1000 Bytes
   239      "consumed": 100 Bytes
   240    }
   241    "3"{
   242      "consumed": 2 KB
   243    }
   244    "4"{
   245      "consumed": 3 MB
   246    }
   247    "5"{
   248      "consumed": 4 GB
   249    }
   250  }
   251  `)
   252  }
   253  
   254  func (s *testSuite) TestMaxConsumed(c *C) {
   255  	r := NewTracker(1, -1)
   256  	c1 := NewTracker(2, -1)
   257  	c2 := NewTracker(3, -1)
   258  	cc1 := NewTracker(4, -1)
   259  
   260  	c1.AttachTo(r)
   261  	c2.AttachTo(r)
   262  	cc1.AttachTo(c1)
   263  
   264  	ts := []*Tracker{r, c1, c2, cc1}
   265  	var consumed, maxConsumed int64
   266  	for i := 0; i < 10; i++ {
   267  		t := ts[rand.Intn(len(ts))]
   268  		b := rand.Int63n(1000) - 500
   269  		if consumed+b < 0 {
   270  			b = -consumed
   271  		}
   272  		consumed += b
   273  		t.Consume(b)
   274  		maxConsumed = mathutil.MaxInt64(maxConsumed, consumed)
   275  
   276  		c.Assert(r.BytesConsumed(), Equals, consumed)
   277  		c.Assert(r.MaxConsumed(), Equals, maxConsumed)
   278  	}
   279  }
   280  
   281  func (s *testSuite) TestGlobalTracker(c *C) {
   282  	r := NewGlobalTracker(1, -1)
   283  	c1 := NewTracker(2, -1)
   284  	c2 := NewTracker(3, -1)
   285  	c1.Consume(100)
   286  	c2.Consume(200)
   287  
   288  	c1.AttachToGlobalTracker(r)
   289  	c2.AttachToGlobalTracker(r)
   290  	c.Assert(r.BytesConsumed(), Equals, int64(300))
   291  	c.Assert(c1.getParent(), DeepEquals, r)
   292  	c.Assert(c2.getParent(), DeepEquals, r)
   293  	c.Assert(len(r.mu.children), Equals, 0)
   294  
   295  	c1.DetachFromGlobalTracker()
   296  	c2.DetachFromGlobalTracker()
   297  	c.Assert(r.BytesConsumed(), Equals, int64(0))
   298  	c.Assert(c1.getParent(), IsNil)
   299  	c.Assert(c2.getParent(), IsNil)
   300  	c.Assert(len(r.mu.children), Equals, 0)
   301  
   302  	defer func() {
   303  		v := recover()
   304  		c.Assert(v, Equals, "Attach to a non-GlobalTracker")
   305  	}()
   306  	commonTracker := NewTracker(4, -1)
   307  	c1.AttachToGlobalTracker(commonTracker)
   308  
   309  	c1.AttachTo(commonTracker)
   310  	c.Assert(commonTracker.BytesConsumed(), Equals, int64(100))
   311  	c.Assert(len(commonTracker.mu.children), Equals, 1)
   312  	c.Assert(c1.getParent(), DeepEquals, commonTracker)
   313  
   314  	c1.AttachToGlobalTracker(r)
   315  	c.Assert(commonTracker.BytesConsumed(), Equals, int64(0))
   316  	c.Assert(len(commonTracker.mu.children), Equals, 0)
   317  	c.Assert(r.BytesConsumed(), Equals, int64(100))
   318  	c.Assert(c1.getParent(), DeepEquals, r)
   319  	c.Assert(len(r.mu.children), Equals, 0)
   320  
   321  	defer func() {
   322  		v := recover()
   323  		c.Assert(v, Equals, "Detach from a non-GlobalTracker")
   324  	}()
   325  	c2.AttachTo(commonTracker)
   326  	c2.DetachFromGlobalTracker()
   327  
   328  }
   329  
   330  func BenchmarkConsume(b *testing.B) {
   331  	tracker := NewTracker(1, -1)
   332  	b.RunParallel(func(pb *testing.PB) {
   333  		childTracker := NewTracker(2, -1)
   334  		childTracker.AttachTo(tracker)
   335  		for pb.Next() {
   336  			childTracker.Consume(256 << 20)
   337  		}
   338  	})
   339  }
   340  
   341  func (s *testSuite) TestErrorCode(c *C) {
   342  	c.Assert(int(terror.ToALLEGROSQLError(errMemExceedThreshold).Code), Equals, errno.ErrMemExceedThreshold)
   343  }