Skip to content
Open
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
35 changes: 35 additions & 0 deletions .github/actions/setup-kvspace-c/action.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
name: setup-kvspace-c
runs:
using: composite
steps:
- uses: actions/checkout@v4
with:
repository: array2d/blockmalloc
path: blockmalloc
- uses: actions/checkout@v4
with:
repository: array2d/slotsboxmalloc
path: slotsboxmalloc
- uses: actions/checkout@v4
with:
repository: ${{ github.repository_owner }}/kvspace-c
ref: feat/notify-take
path: kvspace-c
- name: Build kvspace-c
shell: bash
run: |
cmake -S blockmalloc -B blockmalloc/build -DCMAKE_BUILD_TYPE=Release
cmake --build blockmalloc/build -j --target blockmalloc
mkdir -p slotsboxmalloc/build kvspace-c/build
gcc -shared -fPIC -O2 -o slotsboxmalloc/build/libslotsboxmalloc.so \
slotsboxmalloc/src/slotsboxmalloc.c \
-Islotsboxmalloc/include -Iblockmalloc/include \
-Lblockmalloc/build -lblockmalloc \
-Wl,-rpath,$GITHUB_WORKSPACE/blockmalloc/build
gcc -shared -fPIC -O2 -o kvspace-c/build/libkvspace-c.so \
kvspace-c/src/xvalue.c kvspace-c/src/kvspace.c kvspace-c/src/durable_abi.c \
-Ikvspace-c/include -Iblockmalloc/include -Islotsboxmalloc/include \
-Lblockmalloc/build -lblockmalloc -Lslotsboxmalloc/build -lslotsboxmalloc \
-lpthread \
-Wl,-rpath,$GITHUB_WORKSPACE/blockmalloc/build \
-Wl,-rpath,$GITHUB_WORKSPACE/slotsboxmalloc/build
77 changes: 28 additions & 49 deletions .github/workflows/ci.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,68 +9,47 @@ on:
workflow_dispatch:

jobs:
# ── 编译 + 静态检查 ──────────────────────────────────────────────────────
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.24"
- run: go mod tidy
- run: go build ./...
path: kvlang
- uses: ./kvlang/.github/actions/setup-kvspace-c
- name: Runtime tests
working-directory: kvlang
run: |
cmake -S runtime -B build/runtime -DCMAKE_BUILD_TYPE=Release -DKVSPACE_LIB=kvspace-c
cmake --build build/runtime --target kvlang_runtime \
kvlang_delegate_test kvlang_notify_test kvlang_incr_test \
kvlang_expire_test kvlang_watchany_test -j
./bin/kvlang_delegate_test
./bin/kvlang_notify_test
./bin/kvlang_incr_test
./bin/kvlang_expire_test
./bin/kvlang_watchany_test

# ── tutorial 集成测试(需要 Redis)────────────────────────────────────────
tutorial-test:
runs-on: ubuntu-latest
services:
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.24"
- run: go mod tidy
- run: go build -o kvlang ./cmd/kvlang/
- run: go install github.com/array2d/kvspace-go/cmd/kvspace@latest
- run: python3 -m unittest tutorial.test.BenchmarkTest
- run: python3 tutorial/test.py
path: kvlang
- uses: ./kvlang/.github/actions/setup-kvspace-c
- uses: dtolnay/rust-toolchain@stable
- name: make shm
working-directory: kvlang
run: mkdir -p bin && make shm -j
- name: tutorial
working-directory: kvlang
env:
KVSPACE: shm:///tmp/kvlang_ci
LD_LIBRARY_PATH: ${{ github.workspace }}/kvspace-c/build:${{ github.workspace }}/blockmalloc/build:${{ github.workspace }}/slotsboxmalloc/build
run: python3 tutorial/test.py --no-build

# ── 多平台交叉编译(仅 tag 时生成 release 产物)─────────────────────────
release:
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.24"

- name: Cross-compile
run: |
go mod tidy
mkdir -p dist
for GOOS in linux darwin; do
for GOARCH in amd64 arm64; do
echo "Building $GOOS/$GOARCH..."
GOOS=$GOOS GOARCH=$GOARCH go build -ldflags="-s -w" -o dist/kvlang-$GOOS-$GOARCH ./cmd/kvlang/
done
done
ls -lh dist/

- name: Create Release
uses: softprops/action-gh-release@v2
with:
files: dist/*
generate_release_notes: true
- run: echo "0.2.0 release artifacts are built with make shm; Go dist is retired"
30 changes: 24 additions & 6 deletions layout/src/code.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,11 +34,11 @@ pub fn compile(kv: &mut Kv, src: &str) -> Result<(), String> {
for func in &file.funcs {
let pkg = if func.pkg.is_empty() { file.package.clone() } else { func.pkg.clone() };
let mut lowered = lower::lower_func(func);
write_func(kv, &pkg, &mut lowered);
write_func(kv, &pkg, &mut lowered)?;
any_code = true;
}
for decl in &file.rwir_decls {
write_rwir_decl(kv, decl);
write_rwir_decl(kv, decl)?;
}

let mut body = file.init_body.clone();
Expand All@@ -53,7 +53,7 @@ pub fn compile(kv: &mut Kv, src: &str) -> Result<(), String> {
pkg: String::new(),
};
let mut lowered = lower::lower_func(&init_fn);
write_func(kv, "", &mut lowered);
write_func(kv, "", &mut lowered)?;
any_code = true;
}

Expand DownExpand Up@@ -100,10 +100,21 @@ pub fn vet(src: &str) -> Result<(), String> {
}

/// 写函数到 /lib/:签名(rwfunc)、源码、参数 Ptr、指令体。
pub fn write_func(kv: &mut Kv, pkg: &str, fn_: &mut Func) {
pub fn write_func(kv: &mut Kv, pkg: &str, fn_: &mut Func) -> Result<(), String> {
let mut type_map = lower::infer_types(fn_);
lower::specialize(fn_, &type_map);
let func_dir = keytree::lib_func(pkg, &fn_.sig.name);
let opcode = if pkg.is_empty() {
fn_.sig.name.clone()
} else {
format!("{}{}{}", pkg, keytree::MEMBER_SEP, fn_.sig.name)
};
let existing = kv.get_one(&keytree::rwir(&opcode));
if kvkind::kind(&existing) == kvkind::KIND_RWIR {
return Err(format!(
"{opcode}: rwir declaration and rwfunc body both define it; one opcode, one definition"
));
}

// 按函数覆盖(文件夹复制式合并):只 del_tree 本函数子树,不动 /lib 下其它函数。
// 禁止整库删除——layoutcode 必须可增量:多次 layout 各自覆盖其函数,不误删先前的函数。
Expand DownExpand Up@@ -134,16 +145,23 @@ pub fn write_func(kv: &mut Kv, pkg: &str, fn_: &mut Func) {
let _ = kv.set(&pairs);

write_body(kv, pkg, &fn_.sig.name, &fn_.body, &mut type_map, 1);
Ok(())
}

/// 写用户声明的 rwir(无体)到 /lib/<opcode>。
pub fn write_rwir_decl(kv: &mut Kv, decl: &RwirDecl) {
pub fn write_rwir_decl(kv: &mut Kv, decl: &RwirDecl) -> Result<(), String> {
let mut opcode = decl.sig.name.clone();
if !decl.pkg.is_empty() {
opcode = format!("{}{}{opcode}", decl.pkg, keytree::MEMBER_SEP);
}
let sig = kv.get_one(&format!("{}/[0,0]", keytree::lib_func("", &opcode)));
if kvkind::kind(&sig) == kvkind::KIND_RWFUNC {
return Err(format!(
"{opcode}: rwir declaration and rwfunc body both define it; one opcode, one definition"
));
}
let v = kvkind::new_rwir(decl.sig.num_reads(), decl.sig.num_writes(), &decl.sig.kindexp_list().join("\n"));
let _ = kv.set(&[(keytree::rwir(&opcode), v)]);
kv.set(&[(keytree::rwir(&opcode), v)])
}

/// 将 body 写入 /lib/<pkg>/<name>/ 下。offset 起始 idx(顶层函数=1)。
Expand Down
8 changes: 8 additions & 0 deletions layout/tests/pipeline_test.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,14 @@ fn fresh_kv() -> Kv {
kv
}

#[test]
fn refuse_rwir_and_rwfunc() {
let mut kv = fresh_kv();
compile(&mut kv, "rwfunc dup() -> () {\n 1 -> _\n}\n").unwrap();
let err = compile(&mut kv, "rwir dup() -> ()\n").unwrap_err();
assert!(err.contains("one opcode, one definition"), "{err}");
}

#[test]
fn compile_simple_func() {
let mut kv = fresh_kv();
Expand Down
36 changes: 35 additions & 1 deletion runtime/CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${BIN_DIR}")
add_library(kvlang_runtime SHARED
src/strbuf.c src/xvalue.c src/kv.c src/keytree.c src/rwir.c
src/vthread.c src/logx.c src/builtin.c src/kvcpu.c src/runtime.c src/rwirext.c
src/type_expr.c)
src/type_expr.c src/dispatch.c)
target_include_directories(kvlang_runtime PUBLIC include src)
target_compile_definitions(kvlang_runtime PRIVATE _GNU_SOURCE)

Expand All@@ -41,3 +41,37 @@ target_link_libraries(kvlang_runtime PRIVATE m pthread)
# --export-dynamic 供 kvlang(term 扩展)找符号;--disable-new-dtags 使 rpath 转 DT_RPATH(传递),
# 让 runtime → kvspace-c → blockmalloc/slotsboxmalloc 的传递依赖能被 runtime 的 rpath 找到。
set_target_properties(kvlang_runtime PROPERTIES LINK_FLAGS "-Wl,--export-dynamic -Wl,--disable-new-dtags")

add_executable(kvlang_delegate_test tests/delegate_test.c)
target_link_libraries(kvlang_delegate_test PRIVATE kvlang_runtime pthread)
target_include_directories(kvlang_delegate_test PRIVATE include src)
add_executable(kvlang_notify_test tests/notify_contract_test.c)
target_link_libraries(kvlang_notify_test PRIVATE kvlang_runtime pthread)
target_include_directories(kvlang_notify_test PRIVATE include src)
add_executable(kvlang_incr_test tests/incr_test.c)
target_link_libraries(kvlang_incr_test PRIVATE kvlang_runtime pthread)
target_include_directories(kvlang_incr_test PRIVATE include src)
add_executable(kvlang_expire_test tests/expire_test.c)
target_link_libraries(kvlang_expire_test PRIVATE kvlang_runtime pthread)
target_include_directories(kvlang_expire_test PRIVATE include src)
add_executable(kvlang_watchany_test tests/watchany_test.c)
target_link_libraries(kvlang_watchany_test PRIVATE kvlang_runtime pthread)
target_include_directories(kvlang_watchany_test PRIVATE include src)
if(KVSPACE_LIB STREQUAL "kvspace-c")
set_target_properties(kvlang_delegate_test PROPERTIES
BUILD_RPATH "${KVSPACE_C_DIR};${BLOCKMALLOC_DIR};${SLOTSBOXMALLOC_DIR};${BIN_DIR}")
set_target_properties(kvlang_notify_test PROPERTIES
BUILD_RPATH "${KVSPACE_C_DIR};${BLOCKMALLOC_DIR};${SLOTSBOXMALLOC_DIR};${BIN_DIR}")
set_target_properties(kvlang_incr_test PROPERTIES
BUILD_RPATH "${KVSPACE_C_DIR};${BLOCKMALLOC_DIR};${SLOTSBOXMALLOC_DIR};${BIN_DIR}")
set_target_properties(kvlang_expire_test PROPERTIES
BUILD_RPATH "${KVSPACE_C_DIR};${BLOCKMALLOC_DIR};${SLOTSBOXMALLOC_DIR};${BIN_DIR}")
set_target_properties(kvlang_watchany_test PROPERTIES
BUILD_RPATH "${KVSPACE_C_DIR};${BLOCKMALLOC_DIR};${SLOTSBOXMALLOC_DIR};${BIN_DIR}")
else()
set_target_properties(kvlang_delegate_test PROPERTIES BUILD_RPATH "${KVSPACE_DURABLE_DIR};${BIN_DIR}")
set_target_properties(kvlang_notify_test PROPERTIES BUILD_RPATH "${KVSPACE_DURABLE_DIR};${BIN_DIR}")
set_target_properties(kvlang_incr_test PROPERTIES BUILD_RPATH "${KVSPACE_DURABLE_DIR};${BIN_DIR}")
set_target_properties(kvlang_expire_test PROPERTIES BUILD_RPATH "${KVSPACE_DURABLE_DIR};${BIN_DIR}")
set_target_properties(kvlang_watchany_test PROPERTIES BUILD_RPATH "${KVSPACE_DURABLE_DIR};${BIN_DIR}")
endif()
Loading
Loading