matrixorigin / matrixorigin/matrixone

[Bug]: shardservice HasAllLocalReplicas 将远端副本误判为本地副本

Open
#25,874 0 comments 0 reactions 1 assignee Claimed by @XuPeng-SH View on GitHub
kind/bug needs-triage
Dominant language
Go
Stars
1.9k
Forks
311
Avg merge
1d 3h
Merged PRs (30d)
768

Description

### 是否存在相同问题

- [x] 已检索现有 issue。
- 检索到 #19176,但该 issue 的结论是 range/list 分区裁剪缺失;本问题是当前 `shardservice.HasAllLocalReplicas` 丢弃本地性判断结果,根因和白盒复现均不同。

### 分支与提交

- 分支:最新 `main`
- Commit:`826a3e3d294ba62c7c4da217d1445f3c568ce4d9`
- Commit 标题:`fix(colexec): short-circuit flow-control expressions (#25742)`
- 验证日期:2026-07-20

### 问题描述

`pkg/shardservice/service.go` 的 `HasAllLocalReplicas` 用于判断一张表的每个 shard 是否都至少有一个本地 CN 副本。

当前循环调用了 `s.isLocalReplica(replica)`,但没有使用返回值;随后无条件执行 `local++` 并 `break`:

```go
for _, replica := range shard.Replicas {
s.isLocalReplica(replica)
local++
break
}
```

因此,只要每个 shard 的 replica 列表非空,即使所有 replica 都属于其他 CN,也会被计入本地副本数,最终错误返回 `true`。

### 白盒测试用例

构造:

- 当前服务:`ServiceID = cn-local`
- 表 ID:`42`
- shard 1:仅有 `cn-remote-1` 副本
- shard 2:仅有 `cn-remote-2` 副本
- 两个 shard 均没有 `cn-local` 副本

核心断言:

```go
allLocal, err := s.HasAllLocalReplicas(tableID)
require.NoError(t, err)
require.False(t, allLocal,
"remote-only replicas must not be counted as local replicas")
```

### 执行命令

原始代码定向复现:

```bash
go test ./pkg/shardservice \
-run '^TestAuditHasAllLocalReplicasRejectsRemoteOnlyShards$' \
-count=3 -v
```

原始代码 race 复现:

```bash
go test -race ./pkg/shardservice \
-run '^TestAuditHasAllLocalReplicasRejectsRemoteOnlyShards$' \
-count=1 -v
```

临时应用最小修正后的稳定性验证:

```bash
go test ./pkg/shardservice \
-run '^TestAuditHasAllLocalReplicasRejectsRemoteOnlyShards$' \
-count=100

go test -race ./pkg/shardservice \
-run '^TestAuditHasAllLocalReplicasRejectsRemoteOnlyShards$' \
-count=50
```

### 实际结果

原始代码普通测试 3 次全部失败:

```text
Error: Should be false
Messages: remote-only replicas must not be counted as local replicas
--- FAIL: TestAuditHasAllLocalReplicasRejectsRemoteOnlyShards
FAIL
```

原始代码 race 测试同样失败,返回值稳定错误;未发现数据竞争。

临时将循环改为仅在 `isLocalReplica(replica) == true` 时执行 `local++` 后:

- 普通测试:`100/100 PASS`
- race 测试:`50/50 PASS`

验证完成后已撤销生产代码修正,仅保留本地未提交的审计测试;未提交、未推送任何代码。

### 期望结果

只有当表的每一个 shard 都至少存在一个 `replica.CN == s.cfg.ServiceID` 的副本时,`HasAllLocalReplicas` 才应返回 `true`。远端副本不能计入本地副本数。

### 影响评估

该方法公开在 `ShardService` 接口中,返回错误结果可能使调用方误走“全部 shard 均在本地”的执行路径。当前 main 仓库内未检索到生产调用点,因此属于已确认的潜伏逻辑错误,但接口语义与实现明确不一致。

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.