github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/logstore/store/checkpointinfo.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 store
    16  
    17  import (
    18  	"encoding/binary"
    19  	"fmt"
    20  	"io"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    23  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/logstore/entry"
    24  )
    25  
    26  type checkpointInfo struct {
    27  	ranges  *common.ClosedIntervals
    28  	partial map[uint64]*partialCkpInfo
    29  }
    30  
    31  func newCheckpointInfo() *checkpointInfo {
    32  	return &checkpointInfo{
    33  		ranges:  common.NewClosedIntervals(),
    34  		partial: make(map[uint64]*partialCkpInfo),
    35  	}
    36  }
    37  
    38  func (info *checkpointInfo) UpdateWtihRanges(intervals *common.ClosedIntervals) {
    39  	info.ranges.TryMerge(*intervals)
    40  	for lsn := range info.partial {
    41  		if intervals.ContainsInt(lsn) {
    42  			delete(info.partial, lsn)
    43  		}
    44  	}
    45  }
    46  
    47  func (info *checkpointInfo) UpdateWtihPartialCheckpoint(lsn uint64, ckps *partialCkpInfo) {
    48  	if info.ranges.Contains(*common.NewClosedIntervalsByInt(lsn)) {
    49  		return
    50  	}
    51  	partialInfo, ok := info.partial[lsn]
    52  	if !ok {
    53  		partialInfo = newPartialCkpInfo(ckps.size)
    54  		info.partial[lsn] = partialInfo
    55  	}
    56  	partialInfo.MergePartialCkpInfo(ckps)
    57  	if partialInfo.IsAllCheckpointed() {
    58  		info.ranges.TryMerge(*common.NewClosedIntervalsByInt(lsn))
    59  		delete(info.partial, lsn)
    60  	}
    61  }
    62  
    63  func (info *checkpointInfo) UpdateWithCommandInfo(lsn uint64, cmds *entry.CommandInfo) {
    64  	if info.ranges.Contains(*common.NewClosedIntervalsByInt(lsn)) {
    65  		return
    66  	}
    67  	partialInfo, ok := info.partial[lsn]
    68  	if !ok {
    69  		partialInfo = newPartialCkpInfo(cmds.Size)
    70  		info.partial[lsn] = partialInfo
    71  	}
    72  	partialInfo.MergeCommandInfos(cmds)
    73  	if partialInfo.IsAllCheckpointed() {
    74  		info.ranges.TryMerge(*common.NewClosedIntervalsByInt(lsn))
    75  		delete(info.partial, lsn)
    76  	}
    77  }
    78  
    79  func (info *checkpointInfo) MergeCommandMap(cmdMap map[uint64]entry.CommandInfo) {
    80  	ckpedLsn := make([]uint64, 0)
    81  	for lsn, cmds := range cmdMap {
    82  		if info.ranges.Contains(*common.NewClosedIntervalsByInt(lsn)) {
    83  			continue
    84  		}
    85  		partialInfo, ok := info.partial[lsn]
    86  		if !ok {
    87  			partialInfo = newPartialCkpInfo(cmds.Size)
    88  			info.partial[lsn] = partialInfo
    89  		}
    90  		partialInfo.MergeCommandInfos(&cmds)
    91  		if partialInfo.IsAllCheckpointed() {
    92  			ckpedLsn = append(ckpedLsn, lsn)
    93  			delete(info.partial, lsn)
    94  		}
    95  	}
    96  	if len(ckpedLsn) == 0 {
    97  		return
    98  	}
    99  	intervals := common.NewClosedIntervalsBySlice(ckpedLsn)
   100  	info.ranges.TryMerge(*intervals)
   101  }
   102  
   103  func (info *checkpointInfo) MergeCheckpointInfo(ockp *checkpointInfo) {
   104  	info.ranges.TryMerge(*ockp.ranges)
   105  	for lsn, ockpinfo := range ockp.partial {
   106  		ckpinfo, ok := info.partial[lsn]
   107  		if !ok {
   108  			info.partial[lsn] = ockpinfo
   109  		} else {
   110  			if ckpinfo.size != ockpinfo.size {
   111  				panic("logic err")
   112  			}
   113  			ckpinfo.ckps.Or(ockpinfo.ckps)
   114  			if ckpinfo.IsAllCheckpointed() {
   115  				info.ranges.TryMerge(*common.NewClosedIntervalsByInt(lsn))
   116  				delete(info.partial, lsn)
   117  			}
   118  		}
   119  	}
   120  }
   121  
   122  func (info *checkpointInfo) GetCheckpointed() uint64 {
   123  	if info.ranges == nil || len(info.ranges.Intervals) == 0 {
   124  		return 0
   125  	}
   126  	if info.ranges.Intervals[0].Start > 1 {
   127  		return 0
   128  	}
   129  	return info.ranges.Intervals[0].End
   130  }
   131  
   132  func (info *checkpointInfo) String() string {
   133  	s := fmt.Sprintf("range %v, partial ", info.ranges)
   134  	for lsn, partial := range info.partial {
   135  		s = fmt.Sprintf("%s[%d-%v]", s, lsn, partial)
   136  	}
   137  	return s
   138  }
   139  
   140  func (info *checkpointInfo) GetCkpCnt() uint64 {
   141  	cnt := uint64(0)
   142  	cnt += uint64(info.ranges.GetCardinality())
   143  	// cnt += uint64(len(info.partial))
   144  	return cnt
   145  }
   146  
   147  func (info *checkpointInfo) WriteTo(w io.Writer) (n int64, err error) {
   148  	sn, err := info.ranges.WriteTo(w)
   149  	n += sn
   150  	if err != nil {
   151  		return
   152  	}
   153  	length := uint64(len(info.partial))
   154  	if err = binary.Write(w, binary.BigEndian, length); err != nil {
   155  		return
   156  	}
   157  	n += 8
   158  	for lsn, partialInfo := range info.partial {
   159  		if err = binary.Write(w, binary.BigEndian, lsn); err != nil {
   160  			return
   161  		}
   162  		n += 8
   163  		sn, err = partialInfo.WriteTo(w)
   164  		n += sn
   165  		if err != nil {
   166  			return
   167  		}
   168  	}
   169  	return
   170  }
   171  
   172  func (info *checkpointInfo) ReadFrom(r io.Reader) (n int64, err error) {
   173  	info.ranges = common.NewClosedIntervals()
   174  	sn, err := info.ranges.ReadFrom(r)
   175  	n += sn
   176  	if err != nil {
   177  		return
   178  	}
   179  	length := uint64(0)
   180  	if err = binary.Read(r, binary.BigEndian, &length); err != nil {
   181  		return
   182  	}
   183  	n += 8
   184  	for i := 0; i < int(length); i++ {
   185  		lsn := uint64(0)
   186  		if err = binary.Read(r, binary.BigEndian, &lsn); err != nil {
   187  			return
   188  		}
   189  		n += 8
   190  		partial := newPartialCkpInfo(0)
   191  		sn, err = partial.ReadFrom(r)
   192  		n += sn
   193  		if err != nil {
   194  			return
   195  		}
   196  		info.partial[lsn] = partial
   197  	}
   198  	return
   199  }