github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/store/tikv/scan.go (about)

     1  // Copyright 2016 PingCAP, 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 tikv
    15  
    16  import (
    17  	"github.com/insionng/yougam/libraries/golang/protobuf/proto"
    18  	"github.com/insionng/yougam/libraries/juju/errors"
    19  	"github.com/insionng/yougam/libraries/ngaut/log"
    20  	pb "github.com/insionng/yougam/libraries/pingcap/kvproto/pkg/kvrpcpb"
    21  	"github.com/insionng/yougam/libraries/pingcap/tidb/kv"
    22  	"github.com/insionng/yougam/libraries/pingcap/tidb/terror"
    23  )
    24  
    25  // Scanner support tikv scan
    26  type Scanner struct {
    27  	snapshot     *tikvSnapshot
    28  	batchSize    int
    29  	valid        bool
    30  	cache        []*pb.KvPair
    31  	idx          int
    32  	nextStartKey []byte
    33  	eof          bool
    34  }
    35  
    36  func newScanner(snapshot *tikvSnapshot, startKey []byte, batchSize int) (*Scanner, error) {
    37  	// It must be > 1. Otherwise scanner won't skipFirst.
    38  	if batchSize <= 1 {
    39  		batchSize = scanBatchSize
    40  	}
    41  	scanner := &Scanner{
    42  		snapshot:     snapshot,
    43  		batchSize:    batchSize,
    44  		valid:        true,
    45  		nextStartKey: startKey,
    46  	}
    47  	err := scanner.Next()
    48  	if kv.IsErrNotFound(err) {
    49  		return scanner, nil
    50  	}
    51  	return scanner, errors.Trace(err)
    52  }
    53  
    54  // Valid return valid.
    55  func (s *Scanner) Valid() bool {
    56  	return s.valid
    57  }
    58  
    59  // Key return key.
    60  func (s *Scanner) Key() kv.Key {
    61  	if s.valid {
    62  		return s.cache[s.idx].Key
    63  	}
    64  	return nil
    65  }
    66  
    67  // Value return value.
    68  func (s *Scanner) Value() []byte {
    69  	if s.valid {
    70  		return s.cache[s.idx].Value
    71  	}
    72  	return nil
    73  }
    74  
    75  // Next return next element.
    76  func (s *Scanner) Next() error {
    77  	if !s.valid {
    78  		return errors.New("scanner iterator is invalid")
    79  	}
    80  	for {
    81  		s.idx++
    82  		if s.idx >= len(s.cache) {
    83  			if s.eof {
    84  				s.Close()
    85  				return kv.ErrNotExist
    86  			}
    87  			err := s.getData()
    88  			if err != nil {
    89  				s.Close()
    90  				return errors.Trace(err)
    91  			}
    92  			if s.idx >= len(s.cache) {
    93  				continue
    94  			}
    95  		}
    96  		if err := s.resolveCurrentLock(); err != nil {
    97  			s.Close()
    98  			return errors.Trace(err)
    99  		}
   100  		if len(s.Value()) == 0 {
   101  			// nil stands for NotExist, go to next KV pair.
   102  			continue
   103  		}
   104  		return nil
   105  	}
   106  }
   107  
   108  // Close close iterator.
   109  func (s *Scanner) Close() {
   110  	s.valid = false
   111  }
   112  
   113  func (s *Scanner) startTS() uint64 {
   114  	return s.snapshot.version.Ver
   115  }
   116  
   117  func (s *Scanner) resolveCurrentLock() error {
   118  	current := s.cache[s.idx]
   119  	if current.GetError() == nil {
   120  		return nil
   121  	}
   122  	var backoffErr error
   123  	for backoff := txnLockBackoff(); backoffErr == nil; backoffErr = backoff() {
   124  		val, err := s.snapshot.handleKeyError(current.GetError())
   125  		if err != nil {
   126  			if terror.ErrorEqual(err, errInnerRetryable) {
   127  				continue
   128  			}
   129  			return errors.Trace(err)
   130  		}
   131  		current.Error = nil
   132  		current.Value = val
   133  		return nil
   134  	}
   135  	return errors.Annotate(backoffErr, txnRetryableMark)
   136  }
   137  
   138  func (s *Scanner) getData() error {
   139  	log.Debugf("txn getData nextStartKey[%q], txn %d", s.nextStartKey, s.startTS())
   140  
   141  	var backoffErr error
   142  	for backoff := regionMissBackoff(); backoffErr == nil; backoffErr = backoff() {
   143  		region, err := s.snapshot.store.regionCache.GetRegion(s.nextStartKey)
   144  		if err != nil {
   145  			return errors.Trace(err)
   146  		}
   147  		req := &pb.Request{
   148  			Type: pb.MessageType_CmdScan.Enum(),
   149  			CmdScanReq: &pb.CmdScanRequest{
   150  				StartKey: []byte(s.nextStartKey),
   151  				Limit:    proto.Uint32(uint32(s.batchSize)),
   152  				Version:  proto.Uint64(s.startTS()),
   153  			},
   154  		}
   155  		resp, err := s.snapshot.store.SendKVReq(req, region.VerID())
   156  		if err != nil {
   157  			return errors.Trace(err)
   158  		}
   159  		if regionErr := resp.GetRegionError(); regionErr != nil {
   160  			log.Warnf("scanner getData failed: %s", regionErr)
   161  			continue
   162  		}
   163  		cmdScanResp := resp.GetCmdScanResp()
   164  		if cmdScanResp == nil {
   165  			return errors.Trace(errBodyMissing)
   166  		}
   167  
   168  		kvPairs := cmdScanResp.Pairs
   169  		// Check if kvPair contains error, it should be a Lock.
   170  		for _, pair := range kvPairs {
   171  			if keyErr := pair.GetError(); keyErr != nil {
   172  				lock, err := extractLockInfoFromKeyErr(keyErr)
   173  				if err != nil {
   174  					return errors.Trace(err)
   175  				}
   176  				pair.Key = lock.Key
   177  			}
   178  		}
   179  
   180  		s.cache, s.idx = kvPairs, 0
   181  		if len(kvPairs) < s.batchSize {
   182  			// No more data in current Region. Next getData() starts
   183  			// from current Region's endKey.
   184  			s.nextStartKey = region.EndKey()
   185  			if len(region.EndKey()) == 0 {
   186  				// Current Region is the last one.
   187  				s.eof = true
   188  			}
   189  			return nil
   190  		}
   191  		// next getData() starts from the last key in kvPairs (but skip
   192  		// it by appending a '\x00' to the key). Note that next getData()
   193  		// may get an empty response if the Region in fact does not have
   194  		// more data.
   195  		lastKey := kvPairs[len(kvPairs)-1].GetKey()
   196  		s.nextStartKey = kv.Key(lastKey).Next()
   197  		return nil
   198  	}
   199  	return errors.Annotate(backoffErr, txnRetryableMark)
   200  }