github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/acyclic/causet/property/physical_property.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 property
    15  
    16  import (
    17  	"fmt"
    18  
    19  	"github.com/whtcorpsinc/milevadb/memex"
    20  	"github.com/whtcorpsinc/milevadb/soliton/codec"
    21  )
    22  
    23  // wholeTaskTypes records all possible HoTTs of task that a plan can return. For Agg, TopN and Limit, we will try to get
    24  // these tasks one by one.
    25  var wholeTaskTypes = []TaskType{CopSingleReadTaskType, CoFIDeloubleReadTaskType, RootTaskType}
    26  
    27  // Item wraps the column and its order.
    28  type Item struct {
    29  	DefCaus  *memex.DeferredCauset
    30  	Desc bool
    31  }
    32  
    33  // PhysicalProperty stands for the required physical property by parents.
    34  // It contains the orders and the task types.
    35  type PhysicalProperty struct {
    36  	Items []Item
    37  
    38  	// TaskTp means the type of task that an operator requires.
    39  	//
    40  	// It needs to be specified because two different tasks can't be compared
    41  	// with cost directly. e.g. If a copTask takes less cost than a rootTask,
    42  	// we can't sure that we must choose the former one. Because the copTask
    43  	// must be finished and increase its cost in sometime, but we can't make
    44  	// sure the finishing time. So the best way to let the comparison fair is
    45  	// to add TaskType to required property.
    46  	TaskTp TaskType
    47  
    48  	// ExpectedCnt means this operator may be closed after fetching ExpectedCnt
    49  	// records.
    50  	ExpectedCnt float64
    51  
    52  	// hashcode stores the hash code of a PhysicalProperty, will be lazily
    53  	// calculated when function "HashCode()" being called.
    54  	hashcode []byte
    55  
    56  	// whether need to enforce property.
    57  	Enforced bool
    58  }
    59  
    60  // NewPhysicalProperty builds property from columns.
    61  func NewPhysicalProperty(taskTp TaskType, defcaus []*memex.DeferredCauset, desc bool, expectCnt float64, enforced bool) *PhysicalProperty {
    62  	return &PhysicalProperty{
    63  		Items:       ItemsFromDefCauss(defcaus, desc),
    64  		TaskTp:      taskTp,
    65  		ExpectedCnt: expectCnt,
    66  		Enforced:    enforced,
    67  	}
    68  }
    69  
    70  // ItemsFromDefCauss builds property items from columns.
    71  func ItemsFromDefCauss(defcaus []*memex.DeferredCauset, desc bool) []Item {
    72  	items := make([]Item, 0, len(defcaus))
    73  	for _, col := range defcaus {
    74  		items = append(items, Item{DefCaus: col, Desc: desc})
    75  	}
    76  	return items
    77  }
    78  
    79  // AllDefCaussFromSchema checks whether all the columns needed by this physical
    80  // property can be found in the given schemaReplicant.
    81  func (p *PhysicalProperty) AllDefCaussFromSchema(schemaReplicant *memex.Schema) bool {
    82  	for _, col := range p.Items {
    83  		if schemaReplicant.DeferredCausetIndex(col.DefCaus) == -1 {
    84  			return false
    85  		}
    86  	}
    87  	return true
    88  }
    89  
    90  // IsFlashOnlyProp return true if this physical property is only allowed to generate flash related task
    91  func (p *PhysicalProperty) IsFlashOnlyProp() bool {
    92  	return p.TaskTp == CopTiFlashLocalReadTaskType || p.TaskTp == CopTiFlashGlobalReadTaskType
    93  }
    94  
    95  // GetAllPossibleChildTaskTypes enumrates the possible types of tasks for children.
    96  func (p *PhysicalProperty) GetAllPossibleChildTaskTypes() []TaskType {
    97  	if p.TaskTp == RootTaskType {
    98  		return wholeTaskTypes
    99  	}
   100  	// TODO: For CopSingleReadTaskType and CoFIDeloubleReadTaskType, this function should never be called
   101  	return []TaskType{p.TaskTp}
   102  }
   103  
   104  // IsPrefix checks whether the order property is the prefix of another.
   105  func (p *PhysicalProperty) IsPrefix(prop *PhysicalProperty) bool {
   106  	if len(p.Items) > len(prop.Items) {
   107  		return false
   108  	}
   109  	for i := range p.Items {
   110  		if !p.Items[i].DefCaus.Equal(nil, prop.Items[i].DefCaus) || p.Items[i].Desc != prop.Items[i].Desc {
   111  			return false
   112  		}
   113  	}
   114  	return true
   115  }
   116  
   117  // IsEmpty checks whether the order property is empty.
   118  func (p *PhysicalProperty) IsEmpty() bool {
   119  	return len(p.Items) == 0
   120  }
   121  
   122  // HashCode calculates hash code for a PhysicalProperty object.
   123  func (p *PhysicalProperty) HashCode() []byte {
   124  	if p.hashcode != nil {
   125  		return p.hashcode
   126  	}
   127  	hashcodeSize := 8 + 8 + 8 + (16+8)*len(p.Items) + 8
   128  	p.hashcode = make([]byte, 0, hashcodeSize)
   129  	if p.Enforced {
   130  		p.hashcode = codec.EncodeInt(p.hashcode, 1)
   131  	} else {
   132  		p.hashcode = codec.EncodeInt(p.hashcode, 0)
   133  	}
   134  	p.hashcode = codec.EncodeInt(p.hashcode, int64(p.TaskTp))
   135  	p.hashcode = codec.EncodeFloat(p.hashcode, p.ExpectedCnt)
   136  	for _, item := range p.Items {
   137  		p.hashcode = append(p.hashcode, item.DefCaus.HashCode(nil)...)
   138  		if item.Desc {
   139  			p.hashcode = codec.EncodeInt(p.hashcode, 1)
   140  		} else {
   141  			p.hashcode = codec.EncodeInt(p.hashcode, 0)
   142  		}
   143  	}
   144  	return p.hashcode
   145  }
   146  
   147  // String implements fmt.Stringer interface. Just for test.
   148  func (p *PhysicalProperty) String() string {
   149  	return fmt.Sprintf("Prop{defcaus: %v, TaskTp: %s, expectedCount: %v}", p.Items, p.TaskTp, p.ExpectedCnt)
   150  }
   151  
   152  // Clone returns a copy of PhysicalProperty. Currently, this function is only used to build new
   153  // required property for children plan in `exhaustPhysicalCausets`, so we don't copy `Enforced` field
   154  // because if `Enforced` is true, the `Items` must be empty now, this makes `Enforced` meaningless
   155  // for children nodes.
   156  func (p *PhysicalProperty) Clone() *PhysicalProperty {
   157  	prop := &PhysicalProperty{
   158  		Items:       p.Items,
   159  		TaskTp:      p.TaskTp,
   160  		ExpectedCnt: p.ExpectedCnt,
   161  	}
   162  	return prop
   163  }
   164  
   165  // AllSameOrder checks if all the items have same order.
   166  func (p *PhysicalProperty) AllSameOrder() (bool, bool) {
   167  	if len(p.Items) == 0 {
   168  		return true, false
   169  	}
   170  	for i := 1; i < len(p.Items); i++ {
   171  		if p.Items[i].Desc != p.Items[i-1].Desc {
   172  			return false, false
   173  		}
   174  	}
   175  	return true, p.Items[0].Desc
   176  }