1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
name: Coroutines build
on:
push:
branches:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
build-and-test:
name: ${{ matrix.build }} (coroutines)
strategy:
fail-fast: false
matrix:
build:
include:
- build: Linux-x64
os: ubuntu-24.04
- build: Linux-ARM
os: ubuntu-24.04-arm
# The host runner just hosts the container; the actual build happens
# inside `ubuntu:25.10` (see `container:` below). We pin a specific host
# image rather than using `ubuntu-latest` so a GHA runner image rollover
# doesn't silently change anything visible to the build. The container
# image is multi-arch on Docker Hub, so the same `image:` works for
# both x86_64 and aarch64 hosts.
runs-on: ${{ matrix.os }}
container:
# The pinned folly commit (see librocksdb-sys/rocksdb/folly.mk) requires
# liburing >= 2.15 for the io_uring_zcrx_* zero-copy receive APIs used
# in folly/io/async/IoUringZeroCopyBufferPool.cpp. No distro packages
# that yet, so `build_folly.sh` builds it from source into the folly
# scratch dir and the step below puts it on the include and link paths
# for the cargo builds. The image still matters for the toolchain, and
# the cache key below encodes it so changing this invalidates the folly
# cache.
image: ubuntu:25.10
# Folly's getdeps build can take 30-60+ minutes on a cold cache on
# standard GHA runners (small core count, no parallelism flags). 90
# minutes is a comfortable upper bound. With a warm cache the whole
# job finishes in ~15 minutes.
timeout-minutes: 90
steps:
# Containers start minimal. `actions/checkout` needs git + ca-certs and
# the rust toolchain installer needs curl, so install bootstrap tooling
# before any subsequent action runs. Done in a single apt invocation to
# avoid hitting apt-get's lock or paying for two `update`s.
- name: Bootstrap container
run: |
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
ca-certificates curl git sudo
- name: Checkout sources
uses: actions/checkout@v5
with:
submodules: recursive
- name: Install build dependencies
run: |
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
build-essential gcc-14 g++-14 \
cmake ninja-build python3 python3-pip pkg-config patchelf \
wget \
libssl-dev liburing-dev \
zlib1g-dev libbz2-dev autoconf automake libtool \
clang llvm
# Force gcc-14 instead of ubuntu:25.10's default gcc-15. folly's pinned
# libunwind commit (f081cf4...) was written pre-C23 and uses legacy
# K&R-style function declarations (`func()` meaning "unspecified
# arguments"). gcc-15 defaults to `-std=gnu23` for C, where `func()`
# means "no arguments", so calls like `func(s)` in libunwind's tests
# become hard errors. gcc-14 still defaults to `-std=gnu17`, which
# preserves the legacy semantic.
#
# gcc-14 and gcc-15 share the same libstdc++ ABI, so the subsequent
# `cargo build` (which uses gcc-14 here too via cc/c++ alternatives)
# links cleanly against folly's output.
- name: Switch default compiler to gcc-14
run: |
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100
update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-14 100
update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-14 100
gcc --version
g++ --version
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-key: "v1-rust-coroutines"
# Populate the cache from master runs only, not from PR runs.
cache-save-if: ${{ github.ref == 'refs/heads/master' }}
# The folly build's correctness depends on three independent inputs:
# 1. The folly commit (pinned by RocksDB's folly.mk:FOLLY_COMMIT_HASH).
# 2. The exact container image (glibc + libstdc++ + apt package versions).
# 3. The CPU arch (x86_64 vs aarch64).
# All three are encoded in the cache key. The `-v3` suffix lets us bump
# the cache manually if the build script changes in a way that
# invalidates prior caches (v2 was the previous ubuntu-24.04-host build).
- name: Determine folly commit hash
id: folly-hash
run: |
HASH=$(grep -E '^FOLLY_COMMIT_HASH = ' \
librocksdb-sys/rocksdb/folly.mk \
| sed -E 's/^FOLLY_COMMIT_HASH = //')
echo "hash=$HASH" >> "$GITHUB_OUTPUT"
- name: Cache folly install
id: cache-folly
uses: actions/cache@v4
with:
# `build_folly.sh` uses --scratch-path so install artifacts live
# inside the workspace at a predictable location. Cache both that
# and the folly source checkout so a warm hit avoids both the
# clone and the build. Files written by the build:
# librocksdb-sys/folly-build/installed/{folly,boost,...}-*/
# librocksdb-sys/folly-build/{downloads,build,extracted,shipit}/
# librocksdb-sys/rocksdb/third-party/folly/ (source + patches)
path: |
librocksdb-sys/folly-build
librocksdb-sys/rocksdb/third-party/folly
key: folly-${{ runner.os }}-${{ runner.arch }}-ubuntu-25.10-${{ steps.folly-hash.outputs.hash }}-v3
- name: Build folly
if: steps.cache-folly.outputs.cache-hit != 'true'
run: ./scripts/build_folly.sh
- name: Export ROCKSDB_FOLLY_INSTALL_PATH and LD_LIBRARY_PATH
run: |
# folly is compiled against the liburing `build_folly.sh` picked,
# which is usually one it built from source because no distro
# packages a new enough release. Put that same copy ahead of the
# system one here so RocksDB's io_uring code and libfolly.a agree
# on the headers and the runtime library. The file is absent when
# the system liburing was already good enough.
LIBURING_PREFIX_FILE="$PWD/librocksdb-sys/folly-build/liburing-prefix.txt"
if [ -f "$LIBURING_PREFIX_FILE" ]; then
LIBURING_PREFIX=$(cat "$LIBURING_PREFIX_FILE")
echo "Using liburing from $LIBURING_PREFIX"
echo "PKG_CONFIG_PATH=$LIBURING_PREFIX/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" >> "$GITHUB_ENV"
echo "CPATH=$LIBURING_PREFIX/include${CPATH:+:$CPATH}" >> "$GITHUB_ENV"
echo "LIBRARY_PATH=$LIBURING_PREFIX/lib${LIBRARY_PATH:+:$LIBRARY_PATH}" >> "$GITHUB_ENV"
fi
INSTALL_ROOT="$PWD/librocksdb-sys/folly-build/installed"
if [ ! -d "$INSTALL_ROOT" ]; then
echo "Error: $INSTALL_ROOT does not exist after cache restore." >&2
echo "Cache may have been corrupted or build_folly.sh failed." >&2
ls -la librocksdb-sys/folly-build/ || true
exit 1
fi
echo "ROCKSDB_FOLLY_INSTALL_PATH=$INSTALL_ROOT" >> "$GITHUB_ENV"
# folly's getdeps produces libglog and libgflags as shared libs only
# (no static archives). librocksdb-sys/build.rs links them dynamically.
# `cargo:rustc-link-arg` for rpath would only apply to this crate's
# own test binaries (rust-lang/cargo#9554), not to the rust-rocksdb
# crate's test binaries that nextest actually runs - so set
# LD_LIBRARY_PATH for the rest of the job. This matches the
# "Set LD_LIBRARY_PATH" guidance in the README's runtime constraints
# section.
locate_libdir() {
local dep_dir
dep_dir=$(find "$INSTALL_ROOT" -maxdepth 1 -type d -name "$1-*" \
| head -1)
if [ -z "$dep_dir" ]; then
echo "Error: could not find $1-* under $INSTALL_ROOT" >&2
exit 1
fi
if [ -d "$dep_dir/lib64" ]; then
echo "$dep_dir/lib64"
else
echo "$dep_dir/lib"
fi
}
GLOG_LIBDIR=$(locate_libdir glog)
GFLAGS_LIBDIR=$(locate_libdir gflags)
RUNTIME_LIBDIRS="$GLOG_LIBDIR:$GFLAGS_LIBDIR"
if [ -n "${LIBURING_PREFIX:-}" ]; then
RUNTIME_LIBDIRS="$RUNTIME_LIBDIRS:$LIBURING_PREFIX/lib"
fi
echo "LD_LIBRARY_PATH=$RUNTIME_LIBDIRS${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" >> "$GITHUB_ENV"
- uses: taiki-e/install-action@nextest
- name: cargo build --features coroutines,io-uring
run: cargo build --release --features coroutines,io-uring
- name: Run tests with coroutines feature
run: cargo nextest run --release --features coroutines,io-uring
- name: Run doctests with coroutines feature
run: cargo test --doc --release --features coroutines,io-uring