github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/ekv/union_iter.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 ekv
    15  
    16  import (
    17  	"github.com/whtcorpsinc/milevadb/soliton/logutil"
    18  	"go.uber.org/zap"
    19  )
    20  
    21  // UnionIter is the iterator on an UnionStore.
    22  type UnionIter struct {
    23  	dirtyIt    Iterator
    24  	snapshotIt Iterator
    25  
    26  	dirtyValid    bool
    27  	snapshotValid bool
    28  
    29  	curIsDirty bool
    30  	isValid    bool
    31  	reverse    bool
    32  }
    33  
    34  // NewUnionIter returns a union iterator for BufferStore.
    35  func NewUnionIter(dirtyIt Iterator, snapshotIt Iterator, reverse bool) (*UnionIter, error) {
    36  	it := &UnionIter{
    37  		dirtyIt:       dirtyIt,
    38  		snapshotIt:    snapshotIt,
    39  		dirtyValid:    dirtyIt.Valid(),
    40  		snapshotValid: snapshotIt.Valid(),
    41  		reverse:       reverse,
    42  	}
    43  	err := it.uFIDelateCur()
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	return it, nil
    48  }
    49  
    50  // dirtyNext makes iter.dirtyIt go and uFIDelate valid status.
    51  func (iter *UnionIter) dirtyNext() error {
    52  	err := iter.dirtyIt.Next()
    53  	iter.dirtyValid = iter.dirtyIt.Valid()
    54  	return err
    55  }
    56  
    57  // snapshotNext makes iter.snapshotIt go and uFIDelate valid status.
    58  func (iter *UnionIter) snapshotNext() error {
    59  	err := iter.snapshotIt.Next()
    60  	iter.snapshotValid = iter.snapshotIt.Valid()
    61  	return err
    62  }
    63  
    64  func (iter *UnionIter) uFIDelateCur() error {
    65  	iter.isValid = true
    66  	for {
    67  		if !iter.dirtyValid && !iter.snapshotValid {
    68  			iter.isValid = false
    69  			break
    70  		}
    71  
    72  		if !iter.dirtyValid {
    73  			iter.curIsDirty = false
    74  			break
    75  		}
    76  
    77  		if !iter.snapshotValid {
    78  			iter.curIsDirty = true
    79  			// if delete it
    80  			if len(iter.dirtyIt.Value()) == 0 {
    81  				if err := iter.dirtyNext(); err != nil {
    82  					return err
    83  				}
    84  				continue
    85  			}
    86  			break
    87  		}
    88  
    89  		// both valid
    90  		if iter.snapshotValid && iter.dirtyValid {
    91  			snapshotKey := iter.snapshotIt.Key()
    92  			dirtyKey := iter.dirtyIt.Key()
    93  			cmp := dirtyKey.Cmp(snapshotKey)
    94  			if iter.reverse {
    95  				cmp = -cmp
    96  			}
    97  			// if equal, means both have value
    98  			if cmp == 0 {
    99  				if len(iter.dirtyIt.Value()) == 0 {
   100  					// snapshot has a record, but txn says we have deleted it
   101  					// just go next
   102  					if err := iter.dirtyNext(); err != nil {
   103  						return err
   104  					}
   105  					if err := iter.snapshotNext(); err != nil {
   106  						return err
   107  					}
   108  					continue
   109  				}
   110  				// both go next
   111  				if err := iter.snapshotNext(); err != nil {
   112  					return err
   113  				}
   114  				iter.curIsDirty = true
   115  				break
   116  			} else if cmp > 0 {
   117  				// record from snapshot comes first
   118  				iter.curIsDirty = false
   119  				break
   120  			} else {
   121  				// record from dirty comes first
   122  				if len(iter.dirtyIt.Value()) == 0 {
   123  					logutil.BgLogger().Warn("delete a record not exists?",
   124  						zap.Stringer("key", iter.dirtyIt.Key()))
   125  					// jump over this deletion
   126  					if err := iter.dirtyNext(); err != nil {
   127  						return err
   128  					}
   129  					continue
   130  				}
   131  				iter.curIsDirty = true
   132  				break
   133  			}
   134  		}
   135  	}
   136  	return nil
   137  }
   138  
   139  // Next implements the Iterator Next interface.
   140  func (iter *UnionIter) Next() error {
   141  	var err error
   142  	if !iter.curIsDirty {
   143  		err = iter.snapshotNext()
   144  	} else {
   145  		err = iter.dirtyNext()
   146  	}
   147  	if err != nil {
   148  		return err
   149  	}
   150  	err = iter.uFIDelateCur()
   151  	return err
   152  }
   153  
   154  // Value implements the Iterator Value interface.
   155  // Multi columns
   156  func (iter *UnionIter) Value() []byte {
   157  	if !iter.curIsDirty {
   158  		return iter.snapshotIt.Value()
   159  	}
   160  	return iter.dirtyIt.Value()
   161  }
   162  
   163  // Key implements the Iterator Key interface.
   164  func (iter *UnionIter) Key() Key {
   165  	if !iter.curIsDirty {
   166  		return iter.snapshotIt.Key()
   167  	}
   168  	return iter.dirtyIt.Key()
   169  }
   170  
   171  // Valid implements the Iterator Valid interface.
   172  func (iter *UnionIter) Valid() bool {
   173  	return iter.isValid
   174  }
   175  
   176  // Close implements the Iterator Close interface.
   177  func (iter *UnionIter) Close() {
   178  	if iter.snapshotIt != nil {
   179  		iter.snapshotIt.Close()
   180  		iter.snapshotIt = nil
   181  	}
   182  	if iter.dirtyIt != nil {
   183  		iter.dirtyIt.Close()
   184  		iter.dirtyIt = nil
   185  	}
   186  }