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

     1  // Copyright 2015 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 kv
    15  
    16  import (
    17  	"math"
    18  	"math/rand"
    19  	"time"
    20  
    21  	"github.com/insionng/yougam/libraries/juju/errors"
    22  	"github.com/insionng/yougam/libraries/ngaut/log"
    23  )
    24  
    25  // RunInNewTxn will run the f in a new transaction environment.
    26  func RunInNewTxn(store Storage, retryable bool, f func(txn Transaction) error) error {
    27  	var (
    28  		err error
    29  		txn Transaction
    30  	)
    31  	for i := 0; i < maxRetryCnt; i++ {
    32  		txn, err = store.Begin()
    33  		if err != nil {
    34  			log.Errorf("[kv] RunInNewTxn error - %v", err)
    35  			return errors.Trace(err)
    36  		}
    37  
    38  		err = f(txn)
    39  		if retryable && IsRetryableError(err) {
    40  			log.Warnf("[kv] Retry txn %v", txn)
    41  			txn.Rollback()
    42  			continue
    43  		}
    44  		if err != nil {
    45  			txn.Rollback()
    46  			return errors.Trace(err)
    47  		}
    48  
    49  		err = txn.Commit()
    50  		if retryable && IsRetryableError(err) {
    51  			log.Warnf("[kv] Retry txn %v", txn)
    52  			txn.Rollback()
    53  			BackOff(i)
    54  			continue
    55  		}
    56  		if err != nil {
    57  			return errors.Trace(err)
    58  		}
    59  		break
    60  	}
    61  	return errors.Trace(err)
    62  }
    63  
    64  var (
    65  	// Max retry count in RunInNewTxn
    66  	maxRetryCnt = 100
    67  	// retryBackOffBase is the initial duration, in microsecond, a failed transaction stays dormancy before it retries
    68  	retryBackOffBase = 1
    69  	// retryBackOffCap is the max amount of duration, in microsecond, a failed transaction stays dormancy before it retries
    70  	retryBackOffCap = 100
    71  )
    72  
    73  // BackOff Implements exponential backoff with full jitter.
    74  // Returns real back off time in microsecond.
    75  // See: http://www.awsarchitectureblog.com/2015/03/backoff.html.
    76  func BackOff(attempts int) int {
    77  	upper := int(math.Min(float64(retryBackOffCap), float64(retryBackOffBase)*math.Pow(2.0, float64(attempts))))
    78  	sleep := time.Duration(rand.Intn(upper)) * time.Millisecond
    79  	time.Sleep(sleep)
    80  	return int(sleep)
    81  }