Repository: pingcap/tidb (Go)

Issue:
transaction limit is different between `insert` and `delete` statements
## Bug Report

Please answer these questions before submitting your issue. Thanks!

### 1. What did you do?

create a table:
```sql
create table t(a varchar(2000), b varchar(2000));
```

insert into lots of values into this table:
```sql
insert into t values(space(2000), space(2000));

-- repeat the following sql to insert data into table t
insert into t select * from t;
```

when reach the transaction limit, continue to insert into some data:
```sql
-- reached the transaction limit:
TiDB(root@127.0.0.1:test) > insert into t select * from t;
ERROR 8004 (HY000): Transaction is too large, size: 104858403

-- continue inserting into this table:
insert into t select * from t limit 10000;
insert into t select * from t limit 10000;
insert into t select * from t limit 10000;
insert into t select * from t limit 10000;
```

now delete from this table:
```sql
delete from t;
```

### 2. What did you expect to see?

the above `delete` statement should exceed the transaction limit and failed

### 3. What did you see instead?

but it successed :joy: :
```sql
TiDB(root@127.0.0.1:test) > delete from t;
Query OK, 72768 rows affected (4.44 sec)
```

### 4. What version of TiDB are you using (`tidb-server -V` or run `select tidb_version();` on TiDB)?

```
➜ ./bin/tidb-server -V
Release Version: v4.0.0-beta-328-g5e89ab0fb
Git Commit Hash: 5e89ab0fb7a694e7cd055335acd37347ffbe84bd
Git Branch: master
UTC Build Time: 2020-03-07 05:26:07
GoVersion: go1.13.8
Race Enabled: false
TiKV Min Version: v3.0.0-60965b006877ca7234adaced7890d7b029ed1306
Check Table Before Drop: false
```




Discussion:
It may be that the transaction limit is limited by the total size of the KVs. Insert is the complete key and value for writing data, but delete is the write key and value is nil, so more rows are allowed to be deleted.
Both @zz-jason and @jackysp  are right.

1. Delete doesn't check the transaction size during writing the memBuffer as Set does.
2. The `delete` statement doesn't report transaction too large error because the key size is too small.
3. `delete from t` checks the transaction size in 2pc.go

If I make the value smaller, I can make `delete` report error, however, the stack is different from `set`:

```
mysql> insert into t select * from t;
ERROR 8004 (HY000): Transaction is too large, size: 10485762
mysql> delete from t;
ERROR 8004 (HY000): Transaction is too large, size: 47961472


github.com/pingcap/errors.AddStack
	C:/project/pkg/mod/github.com/pingcap/errors@v0.11.5-0.20190809092503-95897b64e011/errors.go:174
github.com/pingcap/parser/terror.(*Error).GenWithStackByArgs
	C:/project/pkg/mod/github.com/pingcap/parser@v0.0.0-20200305120128-bde9faa0df84/terror/terror.go:243
github.com/pingcap/tidb/kv.(*memDbBuffer).Set
	C:/project/src/github.com/pingcap/tidb/kv/memdb_buffer.go:106
github.com/pingcap/tidb/session.(*TxnState).Set
	C:/project/src/github.com/pingcap/tidb/session/txn.go:290
github.com/pingcap/tidb/table/tables.(*TableCommon).AddRecord
	C:/project/src/github.com/pingcap/tidb/table/tables/tables.go:574
github.com/pingcap/tidb/executor.(*InsertValues).addRecord
	C:/project/src/github.com/pingcap/tidb/executor/insert_common.go:1006
github.com/pingcap/tidb/executor.(*InsertExec).exec
	C:/project/src/github.com/pingcap/tidb/executor/insert.go:85
github.com/pingcap/tidb/executor.insertRowsFromSelect
	C:/project/src/github.com/pingcap/tidb/executor/insert_common.go:447
github.com/pingcap/tidb/executor.(*InsertExec).Next
	C:/project/src/github.com/pingcap/tidb/executor/insert.go:254
github.com/pingcap/tidb/executor.Next
	C:/project/src/github.com/pingcap/tidb/executor/executor.go:213
github.com/pingcap/tidb/executor.(*ExecStmt).handleNoDelayExecutor
	C:/project/src/github.com/pingcap/tidb/executor/adapter.go:516
github.com/pingcap/tidb/executor.(*ExecStmt).handleNoDelay
	C:/project/src/github.com/pingcap/tidb/executor/adapter.go:395
github.com/pingcap/tidb/executor.(*ExecStmt).Exec
	C:/project/src/github.com/pingcap/tidb/executor/adapter.go:363
github.com/pingcap/tidb/session.runStmt
	C:/project/src/github.com/pingcap/tidb/session/tidb.go:273
github.com/pingcap/tidb/session.(*session).executeStatement
	C:/project/src/github.com/pingcap/tidb/session/session.go:1041
github.com/pingcap/tidb/session.(*session).execute
	C:/project/src/github.com/pingcap/tidb/session/session.go:1144
github.com/pingcap/tidb/session.(*session).Execute
	C:/project/src/github.com/pingcap/tidb/session/session.go:1080
github.com/pingcap/tidb/server.(*TiDBContext).Execute
	C:/project/src/github.com/pingcap/tidb/server/driver_tidb.go:248
github.com/pingcap/tidb/server.(*clientConn).handleQuery
	C:/project/src/github.com/pingcap/tidb/server/conn.go:1210
github.com/pingcap/tidb/server.(*clientConn).dispatch
	C:/project/src/github.com/pingcap/tidb/server/conn.go:872
github.com/pingcap/tidb/server.(*clientConn).Run
	C:/project/src/github.com/pingcap/tidb/server/conn.go:681
github.com/pingcap/tidb/server.(*Server).onConn
	C:/project/src/github.com/pingcap/tidb/server/server.go:432
runtime.goexit
	c:/go/src/runtime/asm_amd64.s:1357"



github.com/pingcap/errors.AddStack
	C:/project/pkg/mod/github.com/pingcap/errors@v0.11.5-0.20190809092503-95897b64e011/errors.go:174
github.com/pingcap/parser/terror.(*Error).GenWithStackByArgs
	C:/project/pkg/mod/github.com/pingcap/parser@v0.0.0-20200305120128-bde9faa0df84/terror/terror.go:243
github.com/pingcap/tidb/store/tikv.(*twoPhaseCommitter).initKeysAndMutations
	C:/project/src/github.com/pingcap/tidb/store/tikv/2pc.go:352
github.com/pingcap/tidb/store/tikv.(*tikvTxn).Commit
	C:/project/src/github.com/pingcap/tidb/store/tikv/txn.go:230
github.com/pingcap/tidb/session.(*TxnState).Commit
	C:/project/src/github.com/pingcap/tidb/session/txn.go:225
github.com/pingcap/tidb/session.(*session).doCommit
	C:/project/src/github.com/pingcap/tidb/session/session.go:433
github.com/pingcap/tidb/session.(*session).doCommitWithRetry
	C:/project/src/github.com/pingcap/tidb/session/session.go:453
github.com/pingcap/tidb/session.(*session).CommitTxn
	C:/project/src/github.com/pingcap/tidb/session/session.go:512
github.com/pingcap/tidb/session.finishStmt
	C:/project/src/github.com/pingcap/tidb/session/tidb.go:211
github.com/pingcap/tidb/session.runStmt
	C:/project/src/github.com/pingcap/tidb/session/tidb.go:294
github.com/pingcap/tidb/session.(*session).executeStatement
	C:/project/src/github.com/pingcap/tidb/session/session.go:1041
github.com/pingcap/tidb/session.(*session).execute
	C:/project/src/github.com/pingcap/tidb/session/session.go:1144
github.com/pingcap/tidb/session.(*session).Execute
	C:/project/src/github.com/pingcap/tidb/session/session.go:1080
github.com/pingcap/tidb/server.(*TiDBContext).Execute
	C:/project/src/github.com/pingcap/tidb/server/driver_tidb.go:248
github.com/pingcap/tidb/server.(*clientConn).handleQuery
	C:/project/src/github.com/pingcap/tidb/server/conn.go:1210
github.com/pingcap/tidb/server.(*clientConn).dispatch
	C:/project/src/github.com/pingcap/tidb/server/conn.go:872
github.com/pingcap/tidb/server.(*clientConn).Run
	C:/project/src/github.com/pingcap/tidb/server/conn.go:681
github.com/pingcap/tidb/server.(*Server).onConn
	C:/project/src/github.com/pingcap/tidb/server/server.go:432
runtime.goexit
	c:/go/src/runtime/asm_amd64.s:1357"
```


I've file a PR to check the Delete operation

https://github.com/pingcap/tidb/pull/15298



Patch:
diff --git a/kv/memdb_buffer.go b/kv/memdb_buffer.go
index 131c156bfb246..6a9b4842e46bd 100644
--- a/kv/memdb_buffer.go
+++ b/kv/memdb_buffer.go
@@ -111,6 +111,9 @@ func (m *memDbBuffer) Set(k Key, v []byte) error {
 // Delete removes the entry from buffer with provided key.
 func (m *memDbBuffer) Delete(k Key) error {
 	m.db.Put(k, nil)
+	if m.Size() > int(m.bufferSizeLimit) {
+		return ErrTxnTooLarge.GenWithStackByArgs(m.Size())
+	}
 	return nil
 }
 


Test patch:
diff --git a/kv/mem_buffer_test.go b/kv/mem_buffer_test.go
index 297e5da7b55be..fcfe66237e6f5 100644
--- a/kv/mem_buffer_test.go
+++ b/kv/mem_buffer_test.go
@@ -223,6 +223,12 @@ func (s *testKVSuite) TestBufferLimit(c *C) {
 	c.Assert(err, IsNil)
 	err = buffer.Set([]byte("yz"), make([]byte, 499))
 	c.Assert(err, NotNil) // buffer size limit
+
+	err = buffer.Delete(make([]byte, 499))
+	c.Assert(err, IsNil)
+
+	err = buffer.Delete(make([]byte, 500))
+	c.Assert(err, NotNil)
 }
 
 var opCnt = 100000