github.com/matrixorigin/matrixone@v0.7.0/pkg/util/export/batch_processor_test.go (about)

     1  // Copyright 2022 Matrix Origin
     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 export
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"fmt"
    21  	"sync"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    26  	"github.com/matrixorigin/matrixone/pkg/util/stack"
    27  
    28  	"github.com/matrixorigin/matrixone/pkg/logutil"
    29  	"github.com/matrixorigin/matrixone/pkg/util/batchpipe"
    30  	"github.com/matrixorigin/matrixone/pkg/util/errutil"
    31  
    32  	"github.com/google/gops/agent"
    33  	"github.com/stretchr/testify/require"
    34  	"go.uber.org/zap/zapcore"
    35  )
    36  
    37  func init() {
    38  	time.Local = time.FixedZone("CST", 0) // set time-zone +0000
    39  	logutil.SetupMOLogger(&logutil.LogConfig{
    40  		Level:      zapcore.DebugLevel.String(),
    41  		Format:     "console",
    42  		Filename:   "",
    43  		MaxSize:    512,
    44  		MaxDays:    0,
    45  		MaxBackups: 0,
    46  
    47  		DisableStore: true,
    48  	})
    49  	if err := agent.Listen(agent.Options{}); err != nil {
    50  		logutil.Errorf("listen gops agent failed: %s", err)
    51  		return
    52  	}
    53  }
    54  
    55  const NumType = "Num"
    56  
    57  var _ batchpipe.HasName = (*Num)(nil)
    58  var _ batchpipe.ItemBuffer[batchpipe.HasName, any] = &dummyBuffer{}
    59  var _ batchpipe.PipeImpl[batchpipe.HasName, any] = &dummyPipeImpl{}
    60  
    61  type Num int64
    62  
    63  func newDummy(v int64) *Num {
    64  	n := Num(v)
    65  	return &n
    66  }
    67  
    68  func (n Num) GetName() string { return NumType }
    69  
    70  var signalFunc = func() {}
    71  
    72  type dummyBuffer struct {
    73  	batchpipe.Reminder
    74  	arr    []batchpipe.HasName
    75  	mux    sync.Mutex
    76  	signal func()
    77  	ctx    context.Context
    78  }
    79  
    80  func (s *dummyBuffer) Add(item batchpipe.HasName) {
    81  	s.mux.Lock()
    82  	defer s.mux.Unlock()
    83  	ctx := s.ctx
    84  	s.arr = append(s.arr, item)
    85  	if s.signal != nil {
    86  		val := int(*item.(*Num))
    87  		length := len(s.arr)
    88  		logutil.Infof("accept: %v, len: %d", *item.(*Num), length)
    89  		if (val <= 3 && val != length) && (val-3) != length {
    90  			panic(moerr.NewInternalError(ctx, "len not rignt, elem: %d, len: %d", val, length))
    91  		}
    92  		s.signal()
    93  	}
    94  }
    95  func (s *dummyBuffer) Reset() {
    96  	s.mux.Lock()
    97  	defer s.mux.Unlock()
    98  	logutil.Infof("buffer reset, stack: %+v", stack.Callers(0))
    99  	s.arr = s.arr[0:0]
   100  }
   101  func (s *dummyBuffer) IsEmpty() bool {
   102  	s.mux.Lock()
   103  	defer s.mux.Unlock()
   104  	return len(s.arr) == 0
   105  }
   106  func (s *dummyBuffer) ShouldFlush() bool {
   107  	s.mux.Lock()
   108  	defer s.mux.Unlock()
   109  	length := len(s.arr)
   110  	should := length >= 3
   111  	if should {
   112  		logutil.Infof("buffer shouldFlush: %v", should)
   113  	}
   114  	return should
   115  }
   116  func (s *dummyBuffer) GetBatch(ctx context.Context, buf *bytes.Buffer) any {
   117  	s.mux.Lock()
   118  	defer s.mux.Unlock()
   119  	if len(s.arr) == 0 {
   120  		return ""
   121  	}
   122  
   123  	logutil.Infof("GetBatch, len: %d", len(s.arr))
   124  	buf.Reset()
   125  	for _, item := range s.arr {
   126  		s, ok := item.(*Num)
   127  		if !ok {
   128  			panic("Not Num type")
   129  		}
   130  		buf.WriteString("(")
   131  		buf.WriteString(fmt.Sprintf("%d", *s))
   132  		buf.WriteString("),")
   133  	}
   134  	logutil.Infof("GetBatch: %s", buf.String())
   135  	return string(buf.Next(buf.Len() - 1))
   136  }
   137  
   138  type dummyPipeImpl struct {
   139  	ch       chan string
   140  	duration time.Duration
   141  }
   142  
   143  func (n *dummyPipeImpl) NewItemBuffer(string) batchpipe.ItemBuffer[batchpipe.HasName, any] {
   144  	return &dummyBuffer{Reminder: batchpipe.NewConstantClock(n.duration), signal: signalFunc, ctx: context.Background()}
   145  }
   146  
   147  func (n *dummyPipeImpl) NewItemBatchHandler(ctx context.Context) func(any) {
   148  	return func(batch any) {
   149  		n.ch <- batch.(string)
   150  	}
   151  }
   152  
   153  var MOCollectorMux sync.Mutex
   154  
   155  func TestNewMOCollector(t *testing.T) {
   156  	MOCollectorMux.Lock()
   157  	defer MOCollectorMux.Unlock()
   158  	ctx := context.Background()
   159  	ch := make(chan string, 3)
   160  	errutil.SetErrorReporter(func(ctx context.Context, err error, i int) {
   161  		t.Logf("TestNewMOCollector::ErrorReport: %+v", err)
   162  	})
   163  	var signalC = make(chan struct{}, 16)
   164  	var acceptSignal = func() { <-signalC }
   165  	signalFunc = func() { signalC <- struct{}{} }
   166  
   167  	collector := NewMOCollector(ctx)
   168  	collector.Register(newDummy(0), &dummyPipeImpl{ch: ch, duration: time.Hour})
   169  	collector.Start()
   170  
   171  	collector.Collect(ctx, newDummy(1))
   172  	acceptSignal()
   173  	collector.Collect(ctx, newDummy(2))
   174  	acceptSignal()
   175  	collector.Collect(ctx, newDummy(3))
   176  	acceptSignal()
   177  	got := <-ch
   178  	require.Equal(t, `(1),(2),(3)`, got)
   179  	collector.Collect(ctx, newDummy(4))
   180  	acceptSignal()
   181  	collector.Collect(ctx, newDummy(5))
   182  	acceptSignal()
   183  	collector.Stop(true)
   184  	logutil.GetGlobalLogger().Sync()
   185  	got = <-ch
   186  	require.Equal(t, `(4),(5)`, got)
   187  	for i := len(ch); i > 0; i-- {
   188  		got = <-ch
   189  		t.Logf("left ch: %s", got)
   190  	}
   191  }