From b39592c02e8e87337a10ffc66051f17dc8d8b4ff Mon Sep 17 00:00:00 2001 From: ngaut Date: Wed, 28 Oct 2015 13:48:45 +0800 Subject: [PATCH] kv: Do Lock key when create unique index Fix #461 --- kv/index_iter.go | 22 +++++++++++++--------- session.go | 2 +- tidb_test.go | 15 +++++++++++++++ 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/kv/index_iter.go b/kv/index_iter.go index e19004ddeb941..d40c8e3af636e 100644 --- a/kv/index_iter.go +++ b/kv/index_iter.go @@ -159,20 +159,24 @@ func (c *kvIndex) genIndexKey(indexedValues []interface{}, h int64) ([]byte, err // Create creates a new entry in the kvIndex data. // If the index is unique and there already exists an entry with the same key, Create will return ErrKeyExists func (c *kvIndex) Create(txn Transaction, indexedValues []interface{}, h int64) error { - keyBuf, err := c.genIndexKey(indexedValues, h) + key, err := c.genIndexKey(indexedValues, h) if err != nil { return errors.Trace(err) } if !c.unique { // TODO: reconsider value - err = txn.Set(keyBuf, []byte("timestamp?")) + err = txn.Set(key, []byte("timestamp?")) return errors.Trace(err) } // unique index - _, err = txn.Get(keyBuf) + err = txn.LockKeys(key) + if err != nil { + return errors.Trace(err) + } + _, err = txn.Get(key) if IsErrNotFound(err) { - err = txn.Set(keyBuf, encodeHandle(h)) + err = txn.Set(key, encodeHandle(h)) return errors.Trace(err) } @@ -181,11 +185,11 @@ func (c *kvIndex) Create(txn Transaction, indexedValues []interface{}, h int64) // Delete removes the entry for handle h and indexdValues from KV index. func (c *kvIndex) Delete(txn Transaction, indexedValues []interface{}, h int64) error { - keyBuf, err := c.genIndexKey(indexedValues, h) + key, err := c.genIndexKey(indexedValues, h) if err != nil { return errors.Trace(err) } - err = txn.Delete(keyBuf) + err = txn.Delete(key) return errors.Trace(err) } @@ -217,17 +221,17 @@ func (c *kvIndex) Drop(txn Transaction) error { // Seek searches KV index for the entry with indexedValues. func (c *kvIndex) Seek(txn Transaction, indexedValues []interface{}) (iter IndexIterator, hit bool, err error) { - keyBuf, err := c.genIndexKey(indexedValues, 0) + key, err := c.genIndexKey(indexedValues, 0) if err != nil { return nil, false, errors.Trace(err) } - it, err := txn.Seek(keyBuf) + it, err := txn.Seek(key) if err != nil { return nil, false, errors.Trace(err) } // check if hit hit = false - if it.Valid() && it.Key() == string(keyBuf) { + if it.Valid() && it.Key() == string(key) { hit = true } return &indexIter{it: it, idx: c, prefix: c.prefix}, hit, nil diff --git a/session.go b/session.go index 8e4adf2cacb82..44a2a3c580a7e 100644 --- a/session.go +++ b/session.go @@ -256,7 +256,7 @@ func (s *session) ExecRestrictedSQL(ctx context.Context, sql string) (rset.Recor // Check statement for some restriction // For example only support DML on system meta table. // TODO: Add more restrictions. - log.Infof("Executing %s [%s]", st, sql) + log.Infof("Executing %s [%s]", st.OriginText(), sql) ctx.SetValue(&sqlexec.RestrictedSQLExecutorKeyType{}, true) defer ctx.ClearValue(&sqlexec.RestrictedSQLExecutorKeyType{}) rs, err := st.Exec(ctx) diff --git a/tidb_test.go b/tidb_test.go index 3aaa755704610..fa6d38223b2b0 100644 --- a/tidb_test.go +++ b/tidb_test.go @@ -1245,6 +1245,21 @@ func (s *testSessionSuite) TestResultType(c *C) { c.Assert(fs[0].Col.FieldType.Tp, Equals, mysql.TypeString) } +func (s *testSessionSuite) TestIssue461(c *C) { + // Testcase for https://github.com/pingcap/tidb/issues/325 + store := newStore(c, s.dbName) + se1 := newSession(c, store, s.dbName) + mustExecSQL(c, se1, + `CREATE TABLE test ( id int(11) UNSIGNED NOT NULL AUTO_INCREMENT, val int UNIQUE, PRIMARY KEY (id)); `) + mustExecSQL(c, se1, "begin;") + mustExecSQL(c, se1, "insert into test(id, val) values(1, 1);") + se2 := newSession(c, store, s.dbName) + mustExecSQL(c, se2, "begin;") + mustExecSQL(c, se2, "insert into test(id, val) values(1, 1);") + mustExecSQL(c, se2, "commit;") + mustExecFailed(c, se1, "commit;") +} + func (s *testSessionSuite) TestBuiltin(c *C) { store := newStore(c, s.dbName) se := newSession(c, store, s.dbName)