Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,4 @@ third_party/
os/StarryOS-REF
.Ds_Store
starry-*.log
loongarch64-axvisor-guest-tests.md
loongarch64-axvisor-guest-tests.md
84 changes: 84 additions & 0 deletions apps/starry/mysql/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Starry MySQL App

This app prepares an x86_64 Debian rootfs with Oracle MySQL 8.4.6 generic glibc binaries, then runs a StarryOS guest-side SQL workload.

```bash
cargo xtask starry app qemu -t mysql --arch x86_64
```

Only x86_64 Debian/glibc rootfs images are supported. The Oracle generic package is not suitable for aarch64 or Alpine/musl rootfs images.

## Rootfs Preparation

`prebuild.sh` runs on the host/container before QEMU starts:

1. Prepares `tmp/axbuild/rootfs/rootfs-x86_64-debian.img.tar.xz` with `wget --no-check-certificate`.
2. Extracts the Debian rootfs archive into a dedicated MySQL rootfs image.
3. Expands the dedicated image to `5G`.
4. Downloads MySQL 8.4.6 with `wget --no-check-certificate`, unless `MYSQL_TARBALL` or `mysql.tar.xz` is already available.
5. Installs MySQL into `/opt/mysql`.
6. Unpacks runtime dependencies: `libaio`, `libnuma`, and `libncurses`.
7. Writes `/root/mysql-env.sh` with `PATH` and `LD_LIBRARY_PATH`.
8. Adds `/usr/bin/mysql-test.sh` through the app overlay.

The QEMU config uses the generated rootfs:

```text
tmp/axbuild/rootfs/rootfs-x86_64-mysql.img
```

## Interactive Mode

To enter the MySQL client and run SQL manually, use the interactive QEMU config:

```bash
cargo xtask starry app qemu -t mysql --arch x86_64 \
--qemu-config qemu-x86_64-interactive.toml
```

The guest automatically runs:

```sh
/usr/bin/mysql-interactive.sh
```

The script initializes `/opt/mysql/data` if needed, starts `mysqld` in the background, waits until the Unix socket is usable, then enters the MySQL interactive client. Use `exit` to leave the MySQL client and `Ctrl-a x` to exit QEMU.

## Guest Test Flow

`mysql-test.sh` runs automatically inside StarryOS:

1. Initializes `/opt/mysql/data` in the background.
2. Sleeps 30 seconds, then checks `/tmp/mysql-init.log` until `Bootstrapping complete` appears.
3. Stops the initialization process with plain `kill`, then sleeps 3 seconds.
4. Starts `mysqld` in the background with socket `/tmp/mysql.sock`.
5. Sleeps 30 seconds, then waits for `/tmp/mysql.sock` and `/opt/mysql/data/mysqld.pid`.
6. Runs 15 SQL stages with colored `MYSQL_STAGE_PASSED` output.
7. Restarts `mysqld` with a non-graceful exit before the final persistence stage to avoid the known shutdown hang path.

The test intentionally avoids `mysqladmin shutdown`, which currently can hang the guest during MySQL graceful shutdown.

## Coverage

The 15 SQL stages cover:

- version and server metadata
- database and schema creation
- InnoDB tables with constraints
- multi-row inserts and ordered queries
- updates
- secondary indexes and `EXPLAIN`
- joins
- aggregations
- transactions with `COMMIT` and `ROLLBACK`
- temporary tables
- views and information_schema queries
- restart persistence checks

## Configuration

- Guest memory: `2G`
- StarryOS physical memory: `0x8000_0000`
- Rootfs target size: `5G`
- MySQL package cache: `target/mysql`
- Success marker: `MYSQL_TEST_PASSED`
84 changes: 84 additions & 0 deletions apps/starry/mysql/README_CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Starry MySQL 应用

这个应用会先准备一个带 Oracle MySQL 8.4.6 generic glibc 二进制包的 x86_64 Debian rootfs,然后在 StarryOS guest 中运行 SQL 测试。

```bash
cargo xtask starry app qemu -t mysql --arch x86_64
```

当前只支持 x86_64 Debian/glibc rootfs。Oracle generic 包不适合 aarch64,也不适合 Alpine/musl rootfs。

## Rootfs 准备

`prebuild.sh` 在宿主机或容器中、QEMU 启动前执行:

1. 使用 `wget --no-check-certificate` 准备 `tmp/axbuild/rootfs/rootfs-x86_64-debian.img.tar.xz`。
2. 从 Debian rootfs 压缩包解出 MySQL 专用 rootfs。
3. 将专用镜像扩容到 `5G`。
4. 使用 `wget --no-check-certificate` 下载 MySQL 8.4.6;如果已有 `MYSQL_TARBALL` 或 `mysql.tar.xz`,则直接复用。
5. 将 MySQL 安装到 `/opt/mysql`。
6. 解包运行时依赖:`libaio`、`libnuma`、`libncurses`。
7. 写入 `/root/mysql-env.sh`,配置 `PATH` 和 `LD_LIBRARY_PATH`。
8. 通过 app overlay 加入 `/usr/bin/mysql-test.sh`。

QEMU 使用生成后的 rootfs:

```text
tmp/axbuild/rootfs/rootfs-x86_64-mysql.img
```

## 交互模式

如果需要进入 MySQL 客户端手动执行 SQL,可以使用交互配置:

```bash
cargo xtask starry app qemu -t mysql --arch x86_64 \
--qemu-config qemu-x86_64-interactive.toml
```

进入 guest 后会自动运行:

```sh
/usr/bin/mysql-interactive.sh
```

这个脚本会在 `/opt/mysql/data` 尚未初始化时执行初始化,随后后台启动 `mysqld`,等待 socket 可连接,最后进入 MySQL 交互客户端。退出 MySQL 客户端使用 `exit`,退出 QEMU 使用 `Ctrl-a x`。

## Guest 测试流程

`mysql-test.sh` 会在 StarryOS 内自动运行:

1. 后台初始化 `/opt/mysql/data`。
2. 先睡眠 30 秒,然后检查 `/tmp/mysql-init.log`,直到出现 `Bootstrapping complete`。
3. 使用普通 `kill` 停掉初始化进程,然后睡眠 3 秒。
4. 后台启动 `mysqld`,socket 使用 `/tmp/mysql.sock`。
5. 先睡眠 30 秒,然后等待 `/tmp/mysql.sock` 和 `/opt/mysql/data/mysqld.pid` 出现。
6. 执行 15 个 SQL 阶段,并输出带颜色的 `MYSQL_STAGE_PASSED`。
7. 最后一组持久化测试前使用非优雅退出重启 `mysqld`,避免触发当前已知的 shutdown 卡死路径。

测试刻意避开 `mysqladmin shutdown`,因为当前 MySQL 优雅关闭路径可能导致 guest 卡死。

## 覆盖范围

15 个 SQL 阶段覆盖:

- 版本与服务器元数据
- 数据库和 schema 创建
- 带约束的 InnoDB 表
- 多行插入和排序查询
- 更新操作
- 二级索引和 `EXPLAIN`
- 表连接
- 聚合查询
- `COMMIT` 和 `ROLLBACK` 事务
- 临时表
- 视图和 information_schema 查询
- 重启后的持久化检查

## 配置

- Guest 内存:`2G`
- StarryOS 物理内存:`0x8000_0000`
- Rootfs 目标大小:`5G`
- MySQL 包缓存:`target/mysql`
- 成功标记:`MYSQL_TEST_PASSED`
15 changes: 15 additions & 0 deletions apps/starry/mysql/build-x86_64-unknown-none.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
target = "x86_64-unknown-none"
env = { AX_IP = "10.0.2.15", AX_GW = "10.0.2.2" }
axconfig_overrides = ["plat.phys-memory-size=0x8000_0000"]
log = "Warn"
features = [
"ax-hal/x86-pc",
"qemu",
"ax-driver/plat-static",
"ax-driver/virtio-blk",
"ax-driver/virtio-net",
"ax-driver/virtio-gpu",
"ax-driver/virtio-input",
"ax-driver/virtio-socket",
]
plat_dyn = false
102 changes: 102 additions & 0 deletions apps/starry/mysql/mysql-interactive.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/bin/sh
set -e

. /root/mysql-env.sh

mysql_exec() {
/opt/mysql/bin/mysql --no-defaults -uroot --socket=/tmp/mysql.sock "$@"
}

wait_for_init() {
i=0
sleep 30
while [ "$i" -lt 60 ]; do
tail -n 80 /tmp/mysql-init.log || true
if grep -q "Bootstrapping complete" /tmp/mysql-init.log; then
return
fi
if ! kill -0 "$init_pid" 2>/dev/null; then
echo "mysql initialize exited before Bootstrapping complete" >&2
exit 1
fi
i=$((i + 1))
sleep 10
done
echo "mysql initialize timed out" >&2
exit 1
}

initialize_if_needed() {
if [ -d /opt/mysql/data/mysql ]; then
return
fi

echo "MYSQL_INTERACTIVE_PREP initialize"
rm -rf /opt/mysql/data
mkdir -p /opt/mysql/data /tmp /run/mysqld
/opt/mysql/bin/mysqld \
--initialize-insecure \
--user=root \
--basedir=/opt/mysql \
--datadir=/opt/mysql/data \
--console \
--log-error-verbosity=3 \
> /tmp/mysql-init.log 2>&1 &
init_pid=$!

wait_for_init
kill "$init_pid" 2>/dev/null || true
sleep 3
}

wait_for_server() {
i=0
sleep 30
while [ "$i" -lt 180 ]; do
if [ -S /tmp/mysql.sock ] && [ -f /opt/mysql/data/mysqld.pid ] \
&& mysql_exec -e "SELECT VERSION() AS mysql_version;" >/tmp/mysql-interactive-ready.out 2>&1; then
ls -l /tmp/mysql.sock /opt/mysql/data/mysqld.pid 2>/dev/null || true
cat /tmp/mysql-interactive-ready.out || true
return
fi
if ! kill -0 "$server_pid" 2>/dev/null; then
echo "mysqld exited before readiness" >&2
tail -n 120 /tmp/mysqld.log >&2 || true
exit 1
fi
i=$((i + 1))
sleep 10
done
echo "mysqld readiness timed out" >&2
tail -n 120 /tmp/mysqld.log >&2 || true
exit 1
}

start_server_if_needed() {
if mysql_exec -e "SELECT VERSION() AS mysql_version;" >/tmp/mysql-interactive-ready.out 2>&1; then
cat /tmp/mysql-interactive-ready.out || true
return
fi

echo "MYSQL_INTERACTIVE_PREP start"
rm -f /tmp/mysql.sock /opt/mysql/data/mysqld.pid /tmp/mysqld.log
/opt/mysql/bin/mysqld \
--no-defaults \
--user=root \
--basedir=/opt/mysql \
--datadir=/opt/mysql/data \
--socket=/tmp/mysql.sock \
--pid-file=/opt/mysql/data/mysqld.pid \
--console \
--log-error-verbosity=3 \
> /tmp/mysqld.log 2>&1 &
server_pid=$!

wait_for_server
}

initialize_if_needed
start_server_if_needed

echo "MYSQL_INTERACTIVE_READY"
exec /opt/mysql/bin/mysql --no-defaults -uroot --socket=/tmp/mysql.sock
Loading