Skip to content

Commit

Permalink
store: add open store retry
Browse files Browse the repository at this point in the history
  • Loading branch information
c4pt0r committed Dec 1, 2015
1 parent 151e8b1 commit da226e5
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 2 deletions.
6 changes: 5 additions & 1 deletion kv/txn.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
package kv

import (
"strings"

"github.com/juju/errors"
"github.com/ngaut/log"
"github.com/pingcap/tidb/terror"
Expand All @@ -27,7 +29,9 @@ func IsRetryableError(err error) bool {

if terror.ErrorEqual(err, ErrRetryable) ||
terror.ErrorEqual(err, ErrLockConflict) ||
terror.ErrorEqual(err, ErrConditionNotMatch) {
terror.ErrorEqual(err, ErrConditionNotMatch) ||
// HBase exception message will tell you if you should retry or not
strings.Contains(err.Error(), "try again later") {
return true
}

Expand Down
18 changes: 17 additions & 1 deletion tidb.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ const (
EngineGoLevelDBPersistent = "goleveldb://"
EngineBoltDB = "boltdb://"
EngineHBase = "hbase://"
defaultMaxRetries = 30
retrySleepInterval = 500 * time.Millisecond
)

type domainMap struct {
Expand Down Expand Up @@ -285,6 +287,10 @@ func RegisterLocalStore(name string, driver engine.Driver) error {
// Engine is the storage name registered with RegisterStore.
// Schema is the storage specific format.
func NewStore(uri string) (kv.Storage, error) {
return newStoreWithRetry(uri, defaultMaxRetries)
}

func newStoreWithRetry(uri string, maxRetries int) (kv.Storage, error) {
pos := strings.Index(uri, "://")
if pos == -1 {
return nil, errors.Errorf("invalid uri format, must engine://schema")
Expand All @@ -298,7 +304,17 @@ func NewStore(uri string) (kv.Storage, error) {
return nil, errors.Errorf("invalid uri foramt, storage %s is not registered", name)
}

s, err := d.Open(schema)
var err error
var s kv.Storage
for i := 1; i <= maxRetries; i++ {
s, err = d.Open(schema)
if err == nil || !kv.IsRetryableError(err) {
break
}
sleepTime := time.Duration(uint64(retrySleepInterval) * uint64(i))
log.Errorf("Waiting store to get ready, sleep %v and try again...", sleepTime)
time.Sleep(sleepTime)
}
return s, errors.Trace(err)
}

Expand Down
16 changes: 16 additions & 0 deletions tidb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package tidb

import (
"database/sql"
"errors"
"flag"
"fmt"
"os"
Expand Down Expand Up @@ -48,6 +49,12 @@ type testMainSuite struct {
selectSQL string
}

type brokenStore struct{}

func (s *brokenStore) Open(schema string) (kv.Storage, error) {
return nil, errors.New("try again later")
}

func (s *testMainSuite) SetUpSuite(c *C) {
s.dbName = "test_main_db"
s.createDBSQL = fmt.Sprintf("create database if not exists %s;", s.dbName)
Expand Down Expand Up @@ -306,6 +313,15 @@ func (s *testMainSuite) TestitrimSQL(c *C) {
}
}

func (s *testMainSuite) TestRetryOpenStore(c *C) {
begin := time.Now()
RegisterStore("dummy", &brokenStore{})
_, err := newStoreWithRetry("dummy://dummy-store", 3)
c.Assert(err, NotNil)
elapse := time.Since(begin)
c.Assert(uint64(elapse), Greater, uint64(2*time.Second))
}

func sessionExec(c *C, se Session, sql string) ([]rset.Recordset, error) {
se.Execute("BEGIN;")
r, err := se.Execute(sql)
Expand Down

0 comments on commit da226e5

Please sign in to comment.