* fix: uppertable metacache todo:Fix lockkey case difference #846 * increase uppertablename and Fix lockkey case difference #846 * Fix test case difference #846 * Fix test case difference #846 * reduce uppertablename col #846 * reduce uppertablename #846 * fix test #846 --------- Co-authored-by: FengZhang <zfcode@qq.com>tags/v2.0.0-rc01^0
@@ -21,7 +21,6 @@ import ( | |||
"context" | |||
"database/sql" | |||
"fmt" | |||
"strings" | |||
"sync" | |||
"time" | |||
@@ -111,9 +110,8 @@ func (c *BaseTableMetaCache) refresh(ctx context.Context) { | |||
for i := range v { | |||
tm := v[i] | |||
upperTableName := strings.ToUpper(tm.TableName) | |||
if _, ok := c.cache[upperTableName]; ok { | |||
c.cache[upperTableName] = &entry{ | |||
if _, ok := c.cache[tm.TableName]; ok { | |||
c.cache[tm.TableName] = &entry{ | |||
value: tm, | |||
} | |||
} | |||
@@ -159,16 +157,15 @@ func (c *BaseTableMetaCache) GetTableMeta(ctx context.Context, dbName, tableName | |||
defer c.lock.Unlock() | |||
defer conn.Close() | |||
upperTableName := strings.ToUpper(tableName) | |||
v, ok := c.cache[upperTableName] | |||
v, ok := c.cache[tableName] | |||
if !ok { | |||
meta, err := c.trigger.LoadOne(ctx, dbName, upperTableName, conn) | |||
meta, err := c.trigger.LoadOne(ctx, dbName, tableName, conn) | |||
if err != nil { | |||
return types.TableMeta{}, err | |||
} | |||
if meta != nil && !meta.IsEmpty() { | |||
c.cache[upperTableName] = &entry{ | |||
c.cache[tableName] = &entry{ | |||
value: *meta, | |||
lastAccess: time.Now(), | |||
} | |||
@@ -180,7 +177,7 @@ func (c *BaseTableMetaCache) GetTableMeta(ctx context.Context, dbName, tableName | |||
} | |||
v.lastAccess = time.Now() | |||
c.cache[upperTableName] = v | |||
c.cache[tableName] = v | |||
return v.value, nil | |||
} | |||
@@ -93,7 +93,29 @@ func TestBaseTableMetaCache_refresh(t *testing.T) { | |||
args args | |||
want types.TableMeta | |||
}{ | |||
{name: "test-1", | |||
{ | |||
name: "test1", | |||
fields: fields{ | |||
lock: sync.RWMutex{}, | |||
capity: capacity, | |||
size: 0, | |||
expireDuration: EexpireTime, | |||
cache: map[string]*entry{ | |||
"test": { | |||
value: types.TableMeta{}, | |||
lastAccess: time.Now(), | |||
}, | |||
}, | |||
cancel: cancel, | |||
trigger: &mockTrigger{}, | |||
cfg: &mysql.Config{}, | |||
db: &sql.DB{}, | |||
}, | |||
args: args{ctx: ctx}, | |||
want: testdata.MockWantTypesMeta("test"), | |||
}, | |||
{ | |||
name: "test2", | |||
fields: fields{ | |||
lock: sync.RWMutex{}, | |||
capity: capacity, | |||
@@ -109,8 +131,10 @@ func TestBaseTableMetaCache_refresh(t *testing.T) { | |||
trigger: &mockTrigger{}, | |||
cfg: &mysql.Config{}, | |||
db: &sql.DB{}, | |||
}, args: args{ctx: ctx}, | |||
want: testdata.MockWantTypesMeta("test")}, | |||
}, | |||
args: args{ctx: ctx}, | |||
want: testdata.MockWantTypesMeta("TEST"), | |||
}, | |||
} | |||
for _, tt := range tests { | |||
t.Run(tt.name, func(t *testing.T) { | |||
@@ -144,7 +168,12 @@ func TestBaseTableMetaCache_refresh(t *testing.T) { | |||
time.Sleep(time.Second * 3) | |||
c.lock.RLock() | |||
defer c.lock.RUnlock() | |||
assert.Equal(t, c.cache["TEST"].value, tt.want) | |||
assert.Equal(t, c.cache[func() string { | |||
if tt.name == "test2" { | |||
return "TEST" | |||
} | |||
return "test" | |||
}()].value, tt.want) | |||
}) | |||
} | |||
} | |||
@@ -190,7 +219,7 @@ func TestBaseTableMetaCache_GetTableMeta(t *testing.T) { | |||
ColumnNames = []string{"id", "name", "age"} | |||
tableMeta1 = types.TableMeta{ | |||
TableName: "T_USER1", | |||
TableName: "t_user1", | |||
Columns: columns, | |||
Indexs: index, | |||
ColumnNames: ColumnNames, | |||
@@ -229,12 +258,12 @@ func TestBaseTableMetaCache_GetTableMeta(t *testing.T) { | |||
cache := &BaseTableMetaCache{ | |||
trigger: mockTrigger, | |||
cache: map[string]*entry{ | |||
"T_USER": { | |||
value: tableMeta2, | |||
"t_user1": { | |||
value: tableMeta1, | |||
lastAccess: time.Now(), | |||
}, | |||
"T_USER1": { | |||
value: tableMeta1, | |||
"T_USER2": { | |||
value: tableMeta2, | |||
lastAccess: time.Now(), | |||
}, | |||
}, | |||
@@ -71,7 +71,7 @@ func TestBaseExecBuildLockKey(t *testing.T) { | |||
{[]types.ColumnImage{getColumnImage("id", 2), getColumnImage("userId", "user2")}}, | |||
}, | |||
}, | |||
"test_name:1_user1,2_user2", | |||
"TEST_NAME:1_user1,2_user2", | |||
}, | |||
{ | |||
"Three Primary Keys", | |||
@@ -89,7 +89,7 @@ func TestBaseExecBuildLockKey(t *testing.T) { | |||
{[]types.ColumnImage{getColumnImage("id", 3), getColumnImage("userId", "three"), getColumnImage("age", "33")}}, | |||
}, | |||
}, | |||
"test2_name:1_one_11,2_two_22,3_three_33", | |||
"TEST2_NAME:1_one_11,2_two_22,3_three_33", | |||
}, | |||
{ | |||
name: "Single Primary Key", | |||
@@ -105,7 +105,7 @@ func TestBaseExecBuildLockKey(t *testing.T) { | |||
{Columns: []types.ColumnImage{getColumnImage("id", 100)}}, | |||
}, | |||
}, | |||
expected: "single_key:100", | |||
expected: "SINGLE_KEY:100", | |||
}, | |||
{ | |||
name: "Mixed Type Keys", | |||
@@ -121,7 +121,7 @@ func TestBaseExecBuildLockKey(t *testing.T) { | |||
{Columns: []types.ColumnImage{getColumnImage("name", "mike"), getColumnImage("age", 25)}}, | |||
}, | |||
}, | |||
expected: "mixed_key:mike_25", | |||
expected: "MIXED_KEY:mike_25", | |||
}, | |||
{ | |||
name: "Empty Records", | |||
@@ -132,7 +132,7 @@ func TestBaseExecBuildLockKey(t *testing.T) { | |||
}, | |||
}, | |||
records: types.RecordImage{TableName: "empty"}, | |||
expected: "empty:", | |||
expected: "EMPTY:", | |||
}, | |||
{ | |||
name: "Special Characters", | |||
@@ -148,7 +148,7 @@ func TestBaseExecBuildLockKey(t *testing.T) { | |||
{Columns: []types.ColumnImage{getColumnImage("id", "A,b_c")}}, | |||
}, | |||
}, | |||
expected: "special:A,b_c", | |||
expected: "SPECIAL:A,b_c", | |||
}, | |||
{ | |||
name: "Non-existent Key Name", | |||
@@ -164,7 +164,7 @@ func TestBaseExecBuildLockKey(t *testing.T) { | |||
{Columns: []types.ColumnImage{getColumnImage("id", 1)}}, | |||
}, | |||
}, | |||
expected: "error_key:", | |||
expected: "ERROR_KEY:", | |||
}, | |||
{ | |||
name: "Multiple Rows With Nil PK Value", | |||
@@ -182,7 +182,7 @@ func TestBaseExecBuildLockKey(t *testing.T) { | |||
{Columns: []types.ColumnImage{getColumnImage("id", nil)}}, | |||
}, | |||
}, | |||
expected: "nil_pk:,123,", | |||
expected: "NIL_PK:,123,", | |||
}, | |||
{ | |||
name: "PK As Bool And Float", | |||
@@ -199,10 +199,9 @@ func TestBaseExecBuildLockKey(t *testing.T) { | |||
{Columns: []types.ColumnImage{getColumnImage("name", false), getColumnImage("age", 0.0)}}, | |||
}, | |||
}, | |||
expected: "type_pk:true_3.14,false_0", | |||
expected: "TYPE_PK:true_3.14,false_0", | |||
}, | |||
} | |||
for _, tt := range tests { | |||
t.Run(tt.name, func(t *testing.T) { | |||
lockKeys := exec.buildLockKey(&tt.records, tt.metaData) | |||
@@ -247,7 +247,7 @@ func (b *BasicUndoLogBuilder) buildLockKey(rows driver.Rows, meta types.TableMet | |||
lockKeys bytes.Buffer | |||
filedSequence int | |||
) | |||
lockKeys.WriteString(meta.TableName) | |||
lockKeys.WriteString(strings.ToUpper(meta.TableName)) | |||
lockKeys.WriteString(":") | |||
pks := b.GetScanSlice(meta.GetPrimaryKeyOnlyName(), &meta) | |||
@@ -97,7 +97,7 @@ func TestBuildLockKey(t *testing.T) { | |||
{[]types.ColumnImage{getColumnImage("id", 2), getColumnImage("userId", "two")}}, | |||
}, | |||
}, | |||
"test_name:1_one,2_two", | |||
"TEST_NAME:1_one,2_two", | |||
}, | |||
{ | |||
"Three Primary Keys", | |||
@@ -115,7 +115,7 @@ func TestBuildLockKey(t *testing.T) { | |||
{[]types.ColumnImage{getColumnImage("id", 3), getColumnImage("userId", "three"), getColumnImage("age", "33")}}, | |||
}, | |||
}, | |||
"test2_name:1_one_11,2_two_22,3_three_33", | |||
"TEST2_NAME:1_one_11,2_two_22,3_three_33", | |||
}, | |||
{ | |||
name: "Single Primary Key", | |||
@@ -131,7 +131,7 @@ func TestBuildLockKey(t *testing.T) { | |||
{Columns: []types.ColumnImage{getColumnImage("id", 100)}}, | |||
}, | |||
}, | |||
expected: "single_key:100", | |||
expected: "SINGLE_KEY:100", | |||
}, | |||
{ | |||
name: "Mixed Type Keys", | |||
@@ -147,7 +147,7 @@ func TestBuildLockKey(t *testing.T) { | |||
{Columns: []types.ColumnImage{getColumnImage("name", "Alice"), getColumnImage("age", 25)}}, | |||
}, | |||
}, | |||
expected: "mixed_key:Alice_25", | |||
expected: "MIXED_KEY:Alice_25", | |||
}, | |||
{ | |||
name: "Empty Records", | |||
@@ -158,7 +158,7 @@ func TestBuildLockKey(t *testing.T) { | |||
}, | |||
}, | |||
records: types.RecordImage{TableName: "empty"}, | |||
expected: "empty:", | |||
expected: "EMPTY:", | |||
}, | |||
{ | |||
name: "Special Characters", | |||
@@ -174,7 +174,7 @@ func TestBuildLockKey(t *testing.T) { | |||
{Columns: []types.ColumnImage{getColumnImage("id", "a,b_c")}}, | |||
}, | |||
}, | |||
expected: "special:a,b_c", | |||
expected: "SPECIAL:a,b_c", | |||
}, | |||
{ | |||
name: "Non-existent Key Name", | |||
@@ -190,7 +190,7 @@ func TestBuildLockKey(t *testing.T) { | |||
{Columns: []types.ColumnImage{getColumnImage("id", 1)}}, | |||
}, | |||
}, | |||
expected: "error_key:", | |||
expected: "ERROR_KEY:", | |||
}, | |||
} | |||
@@ -34,7 +34,7 @@ func BuildLockKey(records *types.RecordImage, meta types.TableMeta) string { | |||
colIndex int | |||
} | |||
lockKeys.WriteString(meta.TableName) | |||
lockKeys.WriteString(strings.ToUpper(meta.TableName)) | |||
lockKeys.WriteString(":") | |||
keys := meta.GetPrimaryKeyOnlyName() | |||
@@ -17,7 +17,9 @@ | |||
package testdata | |||
import "seata.apache.org/seata-go/pkg/datasource/sql/types" | |||
import ( | |||
"seata.apache.org/seata-go/pkg/datasource/sql/types" | |||
) | |||
func MockWantTypesMeta(tableName string) types.TableMeta { | |||
return types.TableMeta{ | |||