-
Notifications
You must be signed in to change notification settings - Fork 7
424 lines (381 loc) · 18 KB
/
Copy pathbuild.yml
File metadata and controls
424 lines (381 loc) · 18 KB
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
name: Build and test SECONDO
on:
push:
branches: [main]
pull_request:
jobs:
build-linux:
strategy:
fail-fast: false
matrix:
os: ['ubuntu-22.04', 'ubuntu-24.04', 'ubuntu-26.04']
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repo
uses: actions/checkout@v7
- name: Setup ccache
uses: hendrikmuhs/ccache-action@v1.2.23
with:
key: ${{ matrix.os }}
- name: Update packages
run: |
sudo apt-get update
- name: Install packages
run: |
sudo apt-get -y install flex bison gcc g++ libdb5.3 libdb5.3-dev libdb5.3++ libdb5.3++-dev db5.3-util libjpeg-dev libgsl0-dev libreadline-dev librecode-dev libgmp-dev libncurses-dev libxml2-dev libboost-all-dev build-essential default-jdk wget swi-prolog-nox swi-prolog-java swi-prolog libquadmath0 libgmp-dev libgmp10 libboost-all-dev libbison-dev libfl-dev nlohmann-json3-dev
- name: Detect SECONDO build environment
run: |
# Prolog paths/version, Berkeley DB and platform are derived from the
# installed tools by secondo-detect.sh.
export SECONDO_BUILD_DIR="${GITHUB_WORKSPACE}"
export SECONDO_CC="ccache gcc"
export SECONDO_CPP="ccache g++"
./CM-Scripts/secondo-detect.sh --print-vars
./CM-Scripts/secondo-detect.sh --check
{
echo "SECONDO_CC=${SECONDO_CC}"
echo "SECONDO_CPP=${SECONDO_CPP}"
./CM-Scripts/secondo-detect.sh --print-vars
} >> "$GITHUB_ENV"
- name: Show ccache statistics (before build)
run: ccache -s
- name: Build SECONDO
run: |
make -j $(nproc)
- name: Show ccache statistics (after build)
run: ccache -s
# The C++ unit tests are not part of `make`, and run-tests.sh below only
# drives the TTY level suites -- so nothing was exercising the nested list
# storage layer directly. tnestedlist covers the atom types, CopyList and
# the ToString round trip, and exits with its error count.
- name: Test the nested list storage layer
run: |
make -C Tests tnestedlist
Tests/tnestedlist
# BigArray is what NestedList stores its tables in, and tnestedlist never
# grows one far enough to leave its first chunk. tbigarray does, and
# checks the invariant the class is built around: a chunk, once mapped,
# is never moved -- which is what lets a reader dereference an element
# while another thread appends.
- name: Test the BigArray chunked storage
run: |
make -C Tests tbigarray
Tests/tbigarray
- name: Test SECONDO
run: |
cd CM-Scripts/; ./run-tests.sh -tty /tmp/secondotest 12000
- name: Show failed test logs
if: failure()
run: |
for f in "${GITHUB_WORKSPACE}"/bin/*.test.log; do
[ -f "$f" ] || continue
echo "########## $f"; tail -80 "$f"
done
find /tmp/secondotest -type f 2>/dev/null | while read -r f; do
echo "########## $f"; tail -80 "$f"
done || true
# TestClientServer runs from a mktemp -d and normally removes it, so
# anything left here is from a run that was killed before its trap
# could fire -- a hung shutdown. That leftover monitor.log names the
# call the monitor or checkpoint service was wedged in, and it is the
# one artifact that was missing when this last happened.
for d in "${TMPDIR:-/tmp}"/TestClientServer.* /tmp/TestClientServer.*; do
[ -d "$d" ] || continue
find "$d" -type f 2>/dev/null | while read -r f; do
echo "########## $f"; tail -80 "$f"
done
done || true
# -----------------------------------------------------------------------
# Web UI (WebUI/). Build the JS/Python components against the freshly
# built kernel, then bring the whole stack up (SecondoMonitor + FastAPI
# bridge) and confirm SECONDO answers a real query through the REST
# interface. The headless-browser end-to-end tests (WebUI/frontend/e2e)
# are intentionally NOT run here.
# -----------------------------------------------------------------------
- name: Build the SECONDO client library
# The bridge's native module links libsecondo.a, which the top-level
# make does not build.
run: make -C apis/api_cpp/cs
# -----------------------------------------------------------------------
# tnestedlist above drives one thread, and csloadtest's `parse` mode gives
# every thread a NestedList of its own -- so nothing was covering several
# threads on *one* list, which is what NestedList's recursive mutex exists
# for and what the running system actually does: Distributed2 copies each
# worker's result into the global list (ConnectionInfo::simpleCommand) and
# reads it back, and every Out function an operator runs in a worker
# thread uses the global nl too.
#
# Plain first, because the value checks catch corruption on their own;
# then under ThreadSanitizer, which catches the unsynchronized access
# before it corrupts anything. Needs no server, so it runs here rather
# than with the connection tests further down.
#
# --list-mem is what makes this reach the storage layer: it sizes the
# tables to a single page, so BigArray runs out of room within the first
# rounds and has to ftruncate and mremap while the other threads are
# reading through the mapping it is moving. At the default sizes the
# whole workload fits in the mapping made at construction and never grows
# it once. The run prints how far the node table grew and fails if it did
# not outgrow that first mapping, so this cannot lapse unnoticed.
# -----------------------------------------------------------------------
- name: Test concurrent access to one nested list
working-directory: Tests/csloadtest
timeout-minutes: 10
run: |
make
./app --mode shared --threads 8 --rounds 5 --list-mem 1
make tsan-check-sources
make tsan
TSAN_OPTIONS="halt_on_error=0 history_size=4" \
./app-tsan --mode shared --threads 4 --rounds 2 --list-mem 1
- name: Setup Node
uses: actions/setup-node@v7
with:
node-version: '24'
cache: 'npm'
cache-dependency-path: WebUI/frontend/package-lock.json
- name: Build the WebUI frontend
working-directory: WebUI/frontend
run: |
npm ci
npm run build
- name: Build and test the WebUI backend
# Builds the pybind11 module over libsecondo.a and runs the backend
# unit tests (which fake the SECONDO connection, so no monitor needed).
working-directory: WebUI/backend
run: |
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
make -C native
python -m pytest -q
- name: Restore the berlintest database
# A dedicated database home for the WebUI monitor, shared with the
# following steps via $GITHUB_ENV.
run: |
echo "${GITHUB_WORKSPACE}/bin" >> "$GITHUB_PATH"
echo "SECONDO_CONFIG=${GITHUB_WORKSPACE}/bin/SecondoConfig.ini" >> "$GITHUB_ENV"
echo "SECONDO_PARAM_SecondoHome=${RUNNER_TEMP}/webui-dbs" >> "$GITHUB_ENV"
export PATH="${GITHUB_WORKSPACE}/bin:${PATH}"
export SECONDO_CONFIG="${GITHUB_WORKSPACE}/bin/SecondoConfig.ini"
export SECONDO_PARAM_SecondoHome="${RUNNER_TEMP}/webui-dbs"
mkdir -p "$SECONDO_PARAM_SecondoHome"
cd bin
printf 'create database berlintest;\nrestore database berlintest from berlintest;\nclose database;\nquit;\n' \
| ./SecondoTTYBDB
# -----------------------------------------------------------------------
# Closes the loop the restore above opens: write the database back out and
# require it to come back byte for byte.
# -----------------------------------------------------------------------
- name: Save the berlintest database and compare it with the original
working-directory: bin
run: |
saved="${RUNNER_TEMP}/berlintest.saved"
cat > "${RUNNER_TEMP}/save.sec" <<EOF
open database berlintest;
save database to '${saved}';
close database;
quit;
EOF
./SecondoTTYBDB -i "${RUNNER_TEMP}/save.sec"
cmp berlintest "$saved"
- name: Start the SECONDO monitor
working-directory: bin
run: |
nohup ./SecondoMonitor -s > "${RUNNER_TEMP}/secondo-monitor.log" 2>&1 &
echo "SECONDO_MONITOR_PID=$!" >> "$GITHUB_ENV"
for i in $(seq 1 60); do
if (exec 3<>/dev/tcp/127.0.0.1/1234) 2>/dev/null; then
exec 3>&- 3<&-; echo "Monitor is listening on port 1234"; exit 0
fi
sleep 1
done
echo "SECONDO monitor did not come up"; cat "${RUNNER_TEMP}/secondo-monitor.log"; exit 1
- name: Start the WebUI backend bridge
working-directory: WebUI/backend
run: |
. .venv/bin/activate
nohup uvicorn app.main:app --host 127.0.0.1 --port 8000 \
> "${RUNNER_TEMP}/webui-backend.log" 2>&1 &
echo "WEBUI_BACKEND_PID=$!" >> "$GITHUB_ENV"
- name: Query SECONDO through the REST interface
run: |
# Wait for the bridge to accept requests.
for i in $(seq 1 60); do
if curl -sf http://127.0.0.1:8000/api/health > /dev/null; then break; fi
if [ "$i" = 60 ]; then
echo "Backend did not come up"; cat "${RUNNER_TEMP}/webui-backend.log"; exit 1
fi
sleep 1
done
# The first SECONDO command races the monitor's per-connection
# server fork, so retry until the catalog lists BERLINTEST.
echo "== /api/databases =="
dbs=""
for i in $(seq 1 30); do
dbs=$(curl -sf http://127.0.0.1:8000/api/databases || true)
if echo "$dbs" | grep -q BERLINTEST; then break; fi
if [ "$i" = 30 ]; then
echo "BERLINTEST not listed (last response: ${dbs:-<none>})"; exit 1
fi
sleep 1
done
echo "$dbs"
# Open the database and run a real spatial query, keeping the session
# cookie so both land on the same SECONDO connection.
jar="${RUNNER_TEMP}/webui-cookies.txt"
curl -sf -c "$jar" -b "$jar" -X POST http://127.0.0.1:8000/api/query \
-H 'Content-Type: application/json' \
-d '{"command":"open database berlintest"}' > /dev/null
echo "== query mehringdamm =="
res=$(curl -sf -c "$jar" -b "$jar" -X POST http://127.0.0.1:8000/api/query \
-H 'Content-Type: application/json' \
-d '{"command":"query mehringdamm"}')
echo "$res"
# The point value and its GeoJSON conversion must both be present.
echo "$res" | grep -q '(point (9396.0 9871.0))'
echo "$res" | grep -q '"geojson"'
echo "SECONDO answered a query through the REST bridge."
# -----------------------------------------------------------------------
# The client library has to tolerate several connections in one process:
# the WebUI bridge opens one per browser session and runs them in
# parallel. Tests/csloadtest drives it from many threads and checks the
# answers; under ThreadSanitizer it also checks that nothing shared is
# touched without synchronization. Runs against the monitor started above.
# -----------------------------------------------------------------------
- name: Test concurrent client connections
working-directory: Tests/csloadtest
# These two drive a server over a socket, so a wedged connection hangs
# rather than fails; and see the cap on the nested-list step above for
# how a sanitizer run can spin instead of reporting.
timeout-minutes: 10
run: |
make
./app --db berlintest --threads 10 --rounds 5 --expect-binary
- name: Test concurrent client connections under ThreadSanitizer
working-directory: Tests/csloadtest
timeout-minutes: 10
run: |
# Fails if the list of instrumented sources has drifted from the
# archive: an object we forget to instrument makes TSan quietly blind.
make tsan-check-sources
make tsan
# TSan exits 66 when it reports anything, which fails this step.
# halt_on_error=0 so that a failing run lists every race, not just
# the first. Fewer threads and rounds than above: the sanitizer is
# slow, and the races it looks for do not need a large workload.
TSAN_OPTIONS="halt_on_error=0 history_size=4" \
./app-tsan --db berlintest --threads 4 --rounds 2
- name: Stop the WebUI stack
if: always()
run: |
kill "${WEBUI_BACKEND_PID:-}" 2>/dev/null || true
kill "${SECONDO_MONITOR_PID:-}" 2>/dev/null || true
- name: Show WebUI logs on failure
if: failure()
run: |
echo "########## SECONDO monitor"
cat "${RUNNER_TEMP}/secondo-monitor.log" 2>/dev/null || true
echo "########## WebUI backend"
cat "${RUNNER_TEMP}/webui-backend.log" 2>/dev/null || true
build-macos:
# Builds the C++ kernel + TTY, the Java GUI and the embedded-Prolog
# optimizer engine, then runs the full test suite including the optimizer
# test. The optimizer test drives SecondoBDB in "-pl" mode, which embeds
# libswipl from the stock swi-prolog bottle -- no JPL, so no custom Prolog
# build is needed.
strategy:
fail-fast: false
matrix:
# macos-15-intel = Intel (x86_64, /usr/local); macos-15 / macos-26 =
# Apple Silicon (arm64, /opt/homebrew).
os: ['macos-15-intel', 'macos-15', 'macos-26']
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repo
uses: actions/checkout@v7
- name: Setup ccache
uses: hendrikmuhs/ccache-action@v1.2.23
with:
key: ${{ matrix.os }}-${{ runner.arch }}
- name: Install Homebrew packages
run: |
brew update
# Build tools + the external components the SDK used to provide. The
# embedded optimizer links libswipl from the stock swi-prolog bottle;
# no JPL and no custom Prolog build are needed anymore.
brew install flex bison berkeley-db gsl jpeg-turbo boost gmp \
libxml2 readline nlohmann-json swi-prolog
- name: Install Temurin JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '21'
- name: Put keg-only build tools on PATH
run: |
# Homebrew's flex/bison are keg-only; the makefiles call them by name.
echo "$(brew --prefix bison)/bin" >> "$GITHUB_PATH"
echo "$(brew --prefix flex)/bin" >> "$GITHUB_PATH"
- name: Detect SECONDO build environment
run: |
export SECONDO_BUILD_DIR="${GITHUB_WORKSPACE}"
export SECONDO_CC="ccache clang"
export SECONDO_CPP="ccache clang++"
# Source it so LIBRARY_PATH (link-time Homebrew lib dirs) is set here.
source ./CM-Scripts/secondo-detect.sh
./CM-Scripts/secondo-detect.sh --print-vars
./CM-Scripts/secondo-detect.sh --check
{
echo "SECONDO_CC=${SECONDO_CC}"
echo "SECONDO_CPP=${SECONDO_CPP}"
./CM-Scripts/secondo-detect.sh --print-vars
[ -n "${LIBRARY_PATH:-}" ] && echo "LIBRARY_PATH=${LIBRARY_PATH}"
} >> "$GITHUB_ENV"
- name: Show ccache statistics (before build)
run: ccache -s
- name: Build SECONDO
run: |
make -j $(sysctl -n hw.ncpu)
- name: Show ccache statistics (after build)
run: ccache -s
# The C++ unit tests are not part of `make`, and run-tests.sh below only
# drives the TTY level suites -- so nothing was exercising the nested list
# storage layer directly. tnestedlist covers the atom types, CopyList and
# the ToString round trip, and exits with its error count.
- name: Test the nested list storage layer
run: |
make -C Tests tnestedlist
Tests/tnestedlist
# BigArray is what NestedList stores its tables in, and tnestedlist never
# grows one far enough to leave its first chunk. tbigarray does, and
# checks the invariant the class is built around: a chunk, once mapped,
# is never moved -- which is what lets a reader dereference an element
# while another thread appends.
- name: Test the BigArray chunked storage
run: |
make -C Tests tbigarray
Tests/tbigarray
- name: Test SECONDO
run: |
cd CM-Scripts/; ./run-tests.sh -tty /tmp/secondotest 3600
- name: Show failed test logs
if: failure()
run: |
for f in "${GITHUB_WORKSPACE}"/bin/*.test.log; do
[ -f "$f" ] || continue
echo "########## $f"; tail -80 "$f"
done
find /tmp/secondotest -type f 2>/dev/null | while read -r f; do
echo "########## $f"; tail -80 "$f"
done || true
# TestClientServer runs from a mktemp -d and normally removes it, so
# anything left here is from a run that was killed before its trap
# could fire -- a hung shutdown. That leftover monitor.log names the
# call the monitor or checkpoint service was wedged in, and it is the
# one artifact that was missing when this last happened.
for d in "${TMPDIR:-/tmp}"/TestClientServer.* /tmp/TestClientServer.*; do
[ -d "$d" ] || continue
find "$d" -type f 2>/dev/null | while read -r f; do
echo "########## $f"; tail -80 "$f"
done
done || true