github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/logstore/driver/logservicedriver/info.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 logservicedriver
    16  
    17  import (
    18  	"fmt"
    19  	"math"
    20  	"sync"
    21  	"sync/atomic"
    22  	"time"
    23  
    24  	"github.com/RoaringBitmap/roaring/roaring64"
    25  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    26  	"github.com/matrixorigin/matrixone/pkg/logutil"
    27  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    28  )
    29  
    30  var ErrDriverLsnNotFound = moerr.NewInternalErrorNoCtx("driver info: driver lsn not found")
    31  var ErrRetryTimeOut = moerr.NewInternalErrorNoCtx("driver info: retry time out")
    32  
    33  type driverInfo struct {
    34  	addr        map[uint64]*common.ClosedIntervals //logservicelsn-driverlsn TODO drop on truncate
    35  	validLsn    *roaring64.Bitmap
    36  	addrMu      sync.RWMutex
    37  	driverLsn   uint64 //
    38  	syncing     uint64
    39  	synced      uint64
    40  	syncedMu    sync.RWMutex
    41  	driverLsnMu sync.RWMutex
    42  
    43  	truncating             atomic.Uint64 //
    44  	truncatedLogserviceLsn uint64        //
    45  
    46  	appending  uint64
    47  	appended   *common.ClosedIntervals
    48  	appendedMu sync.RWMutex
    49  	commitCond sync.Cond
    50  	inReplay   bool
    51  }
    52  
    53  func newDriverInfo() *driverInfo {
    54  	return &driverInfo{
    55  		addr:        make(map[uint64]*common.ClosedIntervals),
    56  		validLsn:    roaring64.NewBitmap(),
    57  		addrMu:      sync.RWMutex{},
    58  		driverLsnMu: sync.RWMutex{},
    59  		appended:    common.NewClosedIntervals(),
    60  		appendedMu:  sync.RWMutex{},
    61  		commitCond:  *sync.NewCond(new(sync.Mutex)),
    62  	}
    63  }
    64  
    65  func (d *LogServiceDriver) GetCurrSeqNum() uint64 {
    66  	d.driverLsnMu.Lock()
    67  	lsn := d.driverLsn
    68  	d.driverLsnMu.Unlock()
    69  	return lsn
    70  }
    71  func (info *driverInfo) PreReplay() {
    72  	info.inReplay = true
    73  }
    74  func (info *driverInfo) PostReplay() {
    75  	info.inReplay = false
    76  }
    77  func (info *driverInfo) IsReplaying() bool {
    78  	return info.inReplay
    79  }
    80  func (info *driverInfo) onReplay(r *replayer) {
    81  	info.driverLsn = r.maxDriverLsn
    82  	info.synced = r.maxDriverLsn
    83  	info.syncing = r.maxDriverLsn
    84  	if r.minDriverLsn != math.MaxUint64 {
    85  		info.truncating.Store(r.minDriverLsn - 1)
    86  	}
    87  	info.truncatedLogserviceLsn = r.truncatedLogserviceLsn
    88  	info.appended.TryMerge(*common.NewClosedIntervalsBySlice(r.appended))
    89  }
    90  
    91  func (info *driverInfo) onReplayRecordEntry(lsn uint64, driverLsns *common.ClosedIntervals) {
    92  	info.addr[lsn] = driverLsns
    93  	info.validLsn.Add(lsn)
    94  }
    95  
    96  func (info *driverInfo) getNextValidLogserviceLsn(lsn uint64) uint64 {
    97  	info.addrMu.Lock()
    98  	defer info.addrMu.Unlock()
    99  	if info.validLsn.GetCardinality() == 0 {
   100  		return 0
   101  	}
   102  	max := info.validLsn.Maximum()
   103  	if lsn >= max {
   104  		return max
   105  	}
   106  	lsn++
   107  	for !info.validLsn.Contains(lsn) {
   108  		lsn++
   109  	}
   110  	return lsn
   111  }
   112  
   113  func (info *driverInfo) isToTruncate(logserviceLsn, driverLsn uint64) bool {
   114  	maxlsn := info.getMaxDriverLsn(logserviceLsn)
   115  	if maxlsn == 0 {
   116  		return false
   117  	}
   118  	return maxlsn <= driverLsn
   119  }
   120  
   121  func (info *driverInfo) getMaxDriverLsn(logserviceLsn uint64) uint64 {
   122  	info.addrMu.RLock()
   123  	intervals, ok := info.addr[logserviceLsn]
   124  	if !ok {
   125  		info.addrMu.RUnlock()
   126  		return 0
   127  	}
   128  	lsn := intervals.GetMax()
   129  	info.addrMu.RUnlock()
   130  	return lsn
   131  }
   132  
   133  func (info *driverInfo) allocateDriverLsn() uint64 {
   134  	info.driverLsn++
   135  	lsn := info.driverLsn
   136  	return lsn
   137  }
   138  
   139  func (info *driverInfo) getDriverLsn() uint64 {
   140  	info.driverLsnMu.RLock()
   141  	lsn := info.driverLsn
   142  	info.driverLsnMu.RUnlock()
   143  	return lsn
   144  }
   145  
   146  func (info *driverInfo) getAppended() uint64 {
   147  	info.appendedMu.RLock()
   148  	defer info.appendedMu.RUnlock()
   149  	if info.appended == nil || len(info.appended.Intervals) == 0 || info.appended.Intervals[0].Start != 1 {
   150  		return 0
   151  	}
   152  	return info.appended.Intervals[0].End
   153  }
   154  
   155  func (info *driverInfo) retryAllocateAppendLsnWithTimeout(maxPendding uint64, timeout time.Duration) (lsn uint64, err error) {
   156  	lsn, err = info.tryAllocate(maxPendding)
   157  	if err == ErrTooMuchPenddings {
   158  		err = RetryWithTimeout(timeout, func() (shouldReturn bool) {
   159  			info.commitCond.L.Lock()
   160  			lsn, err = info.tryAllocate(maxPendding)
   161  			if err != ErrTooMuchPenddings {
   162  				info.commitCond.L.Unlock()
   163  				return true
   164  			}
   165  			info.commitCond.Wait()
   166  			info.commitCond.L.Unlock()
   167  			lsn, err = info.tryAllocate(maxPendding)
   168  			return err != ErrTooMuchPenddings
   169  		})
   170  	}
   171  	return
   172  }
   173  
   174  func (info *driverInfo) tryAllocate(maxPendding uint64) (lsn uint64, err error) {
   175  	appended := info.getAppended()
   176  	if info.appending-appended >= maxPendding {
   177  		return 0, ErrTooMuchPenddings
   178  	}
   179  	info.appending++
   180  	return info.appending, nil
   181  }
   182  
   183  func (info *driverInfo) logAppend(appender *driverAppender) {
   184  	info.addrMu.Lock()
   185  	array := make([]uint64, 0)
   186  	for key := range appender.entry.meta.addr {
   187  		array = append(array, key)
   188  	}
   189  	info.validLsn.Add(appender.logserviceLsn)
   190  	interval := common.NewClosedIntervalsBySlice(array)
   191  	info.addr[appender.logserviceLsn] = interval
   192  	info.addrMu.Unlock()
   193  	if interval.GetMin() != info.syncing+1 {
   194  		panic(fmt.Sprintf("logic err, expect %d, min is %d", info.syncing+1, interval.GetMin()))
   195  	}
   196  	if len(interval.Intervals) != 1 {
   197  		logutil.Debugf("interval is %v", interval)
   198  		panic("logic err")
   199  	}
   200  	info.syncing = interval.GetMax()
   201  }
   202  
   203  func (info *driverInfo) gcAddr(logserviceLsn uint64) {
   204  	info.addrMu.Lock()
   205  	defer info.addrMu.Unlock()
   206  	lsnToDelete := make([]uint64, 0)
   207  	for serviceLsn := range info.addr {
   208  		if serviceLsn < logserviceLsn {
   209  			lsnToDelete = append(lsnToDelete, serviceLsn)
   210  		}
   211  	}
   212  	for _, lsn := range lsnToDelete {
   213  		delete(info.addr, lsn)
   214  	}
   215  }
   216  
   217  func (info *driverInfo) getSynced() uint64 {
   218  	info.syncedMu.RLock()
   219  	lsn := info.synced
   220  	info.syncedMu.RUnlock()
   221  	return lsn
   222  }
   223  func (info *driverInfo) onAppend(appended []uint64) {
   224  	info.syncedMu.Lock()
   225  	info.synced = info.syncing
   226  	info.syncedMu.Unlock()
   227  
   228  	appendedArray := common.NewClosedIntervalsBySlice(appended)
   229  	info.appendedMu.Lock()
   230  	info.appended.TryMerge(*appendedArray)
   231  	info.appendedMu.Unlock()
   232  
   233  	info.commitCond.L.Lock()
   234  	info.commitCond.Broadcast()
   235  	info.commitCond.L.Unlock()
   236  }
   237  
   238  func (info *driverInfo) tryGetLogServiceLsnByDriverLsn(driverLsn uint64) (uint64, error) {
   239  	lsn, err := info.getLogServiceLsnByDriverLsn(driverLsn)
   240  	if err == ErrDriverLsnNotFound {
   241  		if lsn <= info.getDriverLsn() {
   242  			for i := 0; i < 10; i++ {
   243  				logutil.Infof("retry get logserviceLsn, driverlsn=%d", driverLsn)
   244  				info.commitCond.L.Lock()
   245  				lsn, err = info.getLogServiceLsnByDriverLsn(driverLsn)
   246  				if err == nil {
   247  					info.commitCond.L.Unlock()
   248  					break
   249  				}
   250  				info.commitCond.Wait()
   251  				info.commitCond.L.Unlock()
   252  				if err == nil {
   253  					break
   254  				}
   255  			}
   256  			if err != nil {
   257  				return 0, ErrRetryTimeOut
   258  			}
   259  		}
   260  	}
   261  	return lsn, err
   262  }
   263  
   264  func (info *driverInfo) getLogServiceLsnByDriverLsn(driverLsn uint64) (uint64, error) {
   265  	info.addrMu.RLock()
   266  	defer info.addrMu.RUnlock()
   267  	for lsn, intervals := range info.addr {
   268  		if intervals.Contains(*common.NewClosedIntervalsByInt(driverLsn)) {
   269  			return lsn, nil
   270  		}
   271  	}
   272  	return 0, ErrDriverLsnNotFound
   273  }