Skip to content

Commit 06c4321

Browse files
mjonsszeminzhou
authored andcommitted
unistore: Added error if row is too long to be locked (pingcap#59699)
close pingcap#59651
1 parent b6b2d03 commit 06c4321

File tree

3 files changed

+28
-0
lines changed

3 files changed

+28
-0
lines changed

pkg/executor/insert_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package executor_test
1717
import (
1818
"fmt"
1919
"strconv"
20+
"strings"
2021
"testing"
2122
"time"
2223

@@ -703,3 +704,18 @@ func TestInsertNullInNonStrictMode(t *testing.T) {
703704
tk.MustExec("insert ignore t1 VALUES (4, 4) ON DUPLICATE KEY UPDATE col1 = null")
704705
tk.MustQuery("select * from t1").Check(testkit.RowsWithSep("|", "1|", "2|", "3|", "4|", "5|"))
705706
}
707+
708+
func TestInsertLargeRow(t *testing.T) {
709+
store := testkit.CreateMockStore(t)
710+
tk := testkit.NewTestKit(t, store)
711+
ver := tk.MustQuery("select tidb_version()").Rows()[0][0].(string)
712+
if !strings.Contains(ver, "Store: unistore") {
713+
t.Skipf("Only support 'Store: unistore'\n%s", ver)
714+
}
715+
tk.MustExec("use test")
716+
tk.MustExec("create table t (id int primary key, b longtext)")
717+
tk.MustExec("set tidb_txn_entry_size_limit = 1<<23")
718+
// the unistore arena blocksize is 8MB (8388608 bytes), so Unistore cannot handle larger rows than that!
719+
// since a row cannot span multiple arena blocks.
720+
tk.MustContainErrMsg("insert into t values (1, REPEAT('t',8388493))", "unistore lock entry too big")
721+
}

pkg/store/mockstore/unistore/lockstore/lockstore.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,12 @@ func (ls *MemStore) replace(key, v []byte, hint *Hint, old *node) {
353353
ls.getArena().free(old.addr)
354354
}
355355

356+
// MaxEntrySize will return the maximum entry size for the MemStore
357+
// Any entry larger than this will likely result in failure.
358+
func (ls *MemStore) MaxEntrySize() int {
359+
return ls.getArena().blockSize - nodeHeaderSize - ls.getHeight()*8
360+
}
361+
356362
func (ls *MemStore) newNode(arena *arena, key []byte, v []byte, height int) *node {
357363
// The base level is already allocated in the node struct.
358364
nodeSize := nodeHeaderSize + height*8 + len(key) + len(v)

pkg/store/mockstore/unistore/tikv/write.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package tikv
1616

1717
import (
1818
"bytes"
19+
"fmt"
1920
"math"
2021
"sync"
2122
"sync/atomic"
@@ -166,6 +167,11 @@ func (w writeLockWorker) run() {
166167
// Ignore if the key doesn't exist
167168
ls.DeleteWithHint(entry.Key.UserKey, hint)
168169
default:
170+
// Make sure it fits into an arena block.
171+
if len(entry.Key.UserKey)+len(entry.Value) > ls.MaxEntrySize() {
172+
batch.err = fmt.Errorf("unistore lock entry too big %d > %d", len(entry.Key.UserKey)+len(entry.Value), ls.MaxEntrySize())
173+
break
174+
}
169175
insertCnt++
170176
ls.PutWithHint(entry.Key.UserKey, entry.Value, hint)
171177
}

0 commit comments

Comments
 (0)