github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/pipeline/types.go (about)

     1  // Copyright 2021 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 pipeline
    16  
    17  import (
    18  	"reflect"
    19  
    20  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    21  	"github.com/matrixorigin/matrixone/pkg/vm"
    22  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    23  )
    24  
    25  // Pipeline contains the information associated with a pipeline in a query execution plan.
    26  // A query execution plan may contains one or more pipelines.
    27  // As an example:
    28  //
    29  //	 CREATE TABLE order
    30  //	 (
    31  //	       order_id    INT,
    32  //	       uid          INT,
    33  //	       item_id      INT,
    34  //	       year         INT,
    35  //	       nation       VARCHAR(100)
    36  //	 );
    37  //
    38  //	 CREATE TABLE customer
    39  //	 (
    40  //	       uid          INT,
    41  //	       nation       VARCHAR(100),
    42  //	       city         VARCHAR(100)
    43  //	 );
    44  //
    45  //	 CREATE TABLE supplier
    46  //	 (
    47  //	       item_id      INT,
    48  //	       nation       VARCHAR(100),
    49  //	       city         VARCHAR(100)
    50  //	 );
    51  //
    52  //		SELECT c.city, s.city, sum(o.revenue) AS revenue
    53  //	 FROM customer c, order o, supplier s
    54  //	 WHERE o.uid = c.uid
    55  //	 AND o.item_id = s.item_id
    56  //	 AND c.nation = 'CHINA'
    57  //	 AND s.nation = 'CHINA'
    58  //	 AND o.year >= 1992 and o.year <= 1997
    59  //	 GROUP BY c.city, s.city, o.year
    60  //	 ORDER BY o.year asc, revenue desc;
    61  //
    62  //	 AST PLAN:
    63  //	    order
    64  //	      |
    65  //	    group
    66  //	      |
    67  //	    filter
    68  //	      |
    69  //	    join
    70  //	    /  \
    71  //	   s   join
    72  //	       /  \
    73  //	      l   c
    74  //
    75  // In this example, a possible pipeline is as follows:
    76  //
    77  // pipeline:
    78  // o ⨝ c ⨝ s
    79  //
    80  //	-> σ(c.nation = 'CHINA' ∧  o.year >= 1992 ∧  o.year <= 1997 ∧  s.nation = 'CHINA')
    81  //	-> γ([c.city, s.city, o.year, sum(o.revenue) as revenue], c.city, s.city, o.year)
    82  //	-> τ(o.year asc, revenue desc)
    83  //	-> π(c.city, s.city, revenue)
    84  type Pipeline struct {
    85  	// attrs, column list.
    86  	attrs []string
    87  	// orders to be executed
    88  	instructions vm.Instructions
    89  	reg          *process.WaitRegister
    90  }
    91  
    92  // cleanup do memory release work for whole pipeline.
    93  func (p *Pipeline) cleanup(proc *process.Process, pipelineFailed bool) {
    94  	// clean all the coming batches.
    95  	if pipelineFailed {
    96  		bat := proc.InputBatch()
    97  		if bat != nil {
    98  			bat.Clean(proc.Mp())
    99  		}
   100  		proc.SetInputBatch(nil)
   101  	}
   102  	// clean operator hold memory.
   103  	for i := range p.instructions {
   104  		p.instructions[i].Arg.Free(proc, pipelineFailed)
   105  	}
   106  
   107  	// select all merge receivers
   108  	listeners, alive := newSelectListener(proc.Reg.MergeReceivers)
   109  	for alive != 0 {
   110  		chosen, value, ok := reflect.Select(listeners)
   111  		if !ok {
   112  			break
   113  		}
   114  		pointer := value.UnsafePointer()
   115  		bat := (*batch.Batch)(pointer)
   116  		if bat == nil {
   117  			alive--
   118  			listeners = append(listeners[:chosen], listeners[chosen+1:]...)
   119  			continue
   120  		}
   121  		bat.Clean(proc.Mp())
   122  	}
   123  }
   124  
   125  func newSelectListener(wrs []*process.WaitRegister) ([]reflect.SelectCase, int) {
   126  	listener := make([]reflect.SelectCase, len(wrs))
   127  	for i, mr := range wrs {
   128  		listener[i] = reflect.SelectCase{
   129  			Dir:  reflect.SelectRecv,
   130  			Chan: reflect.ValueOf(mr.Ch),
   131  		}
   132  	}
   133  	return listener, len(wrs)
   134  }