Merge branch 'claude/library-build-container-Dd9Tg' of https://github.com/cozis/TinyDFS into claude/library-build-container-Dd9Tg

This commit is contained in:
2026-02-21 16:00:28 +01:00
4 changed files with 119 additions and 31 deletions
+2 -1
View File
@@ -10,4 +10,5 @@ coverage_html/
*.o *.o
*.a *.a
*.so *.so
examples/example examples/example
.cluster/
+96 -18
View File
@@ -1,25 +1,24 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# cluster.sh - Spin up a ToastyFS cluster and optionally build & run # cluster.sh - Manage a local 3-node ToastyFS cluster.
# an application that links against libtoastyfs.
# #
# Usage: # Usage:
# ./cluster.sh up Start the 3-node cluster # ./cluster.sh up Build the server and start 3 nodes
# ./cluster.sh down Stop the cluster # ./cluster.sh down Stop all nodes
# ./cluster.sh status Show cluster status # ./cluster.sh status Show which nodes are running
# ./cluster.sh logs [node] Tail cluster logs (or a single node) # ./cluster.sh logs [1|2|3] Tail logs (all nodes, or one)
# ./cluster.sh run <source.c> Build the library, compile <source.c> # ./cluster.sh run <source.c> Build the library, compile <source.c>
# against it, start the cluster, run the # against it, start the cluster, run the
# binary, then tear down the cluster. # binary, then tear down the cluster.
# #
# The cluster exposes ports 8081-8083 on localhost, mapped to the three # The three server nodes listen on:
# server nodes. Client applications should connect to: # 127.0.0.1:8081 127.0.0.1:8082 127.0.0.1:8083
# 127.0.0.1:8081 127.0.0.1:8082 127.0.0.1:8083
# #
set -euo pipefail set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$SCRIPT_DIR" CLUSTER_DIR="$SCRIPT_DIR/.cluster"
ADDRS=("127.0.0.1:8081" "127.0.0.1:8082" "127.0.0.1:8083")
usage() { usage() {
sed -n '3,14s/^# \?//p' "$0" sed -n '3,14s/^# \?//p' "$0"
@@ -27,26 +26,105 @@ usage() {
} }
cluster_up() { cluster_up() {
echo "==> Building server image and starting cluster..." echo "==> Building server..."
docker compose up --build -d make -C "$SCRIPT_DIR" toastyfs
mkdir -p "$CLUSTER_DIR"
for i in 1 2 3; do
pidfile="$CLUSTER_DIR/node${i}.pid"
if [ -f "$pidfile" ] && kill -0 "$(cat "$pidfile")" 2>/dev/null; then
echo " Node $i already running (pid $(cat "$pidfile"))"
continue
fi
node_dir="$CLUSTER_DIR/node${i}"
mkdir -p "$node_dir"
# Build argument list: --addr for self, --peer for the others.
args=()
for j in 1 2 3; do
idx=$((j - 1))
if [ "$j" -eq "$i" ]; then
args+=(--addr "${ADDRS[$idx]}")
else
args+=(--peer "${ADDRS[$idx]}")
fi
done
(
cd "$node_dir"
# ServerState is ~40 MB (MetaStore), which exceeds the
# default 8 MB stack. Raise the limit for the server.
ulimit -s unlimited
"$SCRIPT_DIR/toastyfs" "${args[@]}" \
>> "$CLUSTER_DIR/node${i}.log" 2>&1 &
echo $! > "$pidfile"
)
echo " Node $i started (pid $(cat "$pidfile")) on ${ADDRS[$((i-1))]}"
done
echo "==> Cluster is running." echo "==> Cluster is running."
echo " Nodes: 127.0.0.1:8081 127.0.0.1:8082 127.0.0.1:8083"
} }
cluster_down() { cluster_down() {
echo "==> Stopping cluster..." if [ ! -d "$CLUSTER_DIR" ]; then
docker compose down echo "No cluster state found."
return
fi
for i in 1 2 3; do
pidfile="$CLUSTER_DIR/node${i}.pid"
if [ -f "$pidfile" ]; then
pid="$(cat "$pidfile")"
if kill -0 "$pid" 2>/dev/null; then
kill "$pid" 2>/dev/null || true
echo " Node $i stopped (pid $pid)"
else
echo " Node $i was not running"
fi
rm -f "$pidfile"
fi
done
# Clean up node data directories so fresh starts don't trigger
# the crash-recovery path (vsr_boot_marker).
rm -rf "$CLUSTER_DIR"
echo "==> Cluster stopped."
} }
cluster_status() { cluster_status() {
docker compose ps if [ ! -d "$CLUSTER_DIR" ]; then
echo "No cluster state found. Run './cluster.sh up' first."
return
fi
printf "%-8s %-8s %-20s %s\n" "NODE" "PID" "ADDRESS" "STATUS"
for i in 1 2 3; do
pidfile="$CLUSTER_DIR/node${i}.pid"
addr="${ADDRS[$((i-1))]}"
if [ -f "$pidfile" ]; then
pid="$(cat "$pidfile")"
if kill -0 "$pid" 2>/dev/null; then
printf "%-8s %-8s %-20s %s\n" "node$i" "$pid" "$addr" "running"
else
printf "%-8s %-8s %-20s %s\n" "node$i" "$pid" "$addr" "dead"
fi
else
printf "%-8s %-8s %-20s %s\n" "node$i" "-" "$addr" "not started"
fi
done
} }
cluster_logs() { cluster_logs() {
if [ $# -gt 0 ]; then if [ $# -gt 0 ]; then
docker compose logs -f "$1" logfile="$CLUSTER_DIR/node${1}.log"
if [ ! -f "$logfile" ]; then
echo "No log file for node $1."
return 1
fi
tail -f "$logfile"
else else
docker compose logs -f tail -f "$CLUSTER_DIR"/node*.log
fi fi
} }
+9 -8
View File
@@ -36,12 +36,13 @@ static const char *error_name(ToastyFS_Error e)
int main(void) int main(void)
{ {
/* Cluster addresses (mapped via docker-compose ports). */ /* Cluster addresses (mapped via docker-compose ports).
char *addrs[] = { * These must be writable char arrays because parse_addr_arg
"127.0.0.1:8081", * temporarily modifies the string in-place. */
"127.0.0.1:8082", char addr1[] = "127.0.0.1:8081";
"127.0.0.1:8083", char addr2[] = "127.0.0.1:8082";
}; char addr3[] = "127.0.0.1:8083";
char *addrs[] = { addr1, addr2, addr3 };
printf("Connecting to cluster...\n"); printf("Connecting to cluster...\n");
ToastyFS *tfs = toastyfs_init(1, addrs, 3); ToastyFS *tfs = toastyfs_init(1, addrs, 3);
@@ -54,8 +55,8 @@ int main(void)
int ret; int ret;
/* ---- PUT ---- */ /* ---- PUT ---- */
char *key = "hello"; char key[] = "hello";
char *data = "world"; char data[] = "world";
printf("PUT key=\"%s\" data=\"%s\" (%d bytes)\n", printf("PUT key=\"%s\" data=\"%s\" (%d bytes)\n",
key, data, (int)strlen(data)); key, data, (int)strlen(data));
+12 -4
View File
@@ -255,7 +255,14 @@ int main(int argc, char **argv)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int ret; int ret;
ServerState state;
// ServerState is ~40 MB (MetaStore holds 4096 ObjectMeta entries),
// which exceeds the default stack size. Heap-allocate it.
ServerState *state = malloc(sizeof(ServerState));
if (state == NULL) {
fprintf(stderr, "Failed to allocate ServerState\n");
return -1;
}
void* poll_ctxs[POLL_CAPACITY]; void* poll_ctxs[POLL_CAPACITY];
struct pollfd poll_array[POLL_CAPACITY]; struct pollfd poll_array[POLL_CAPACITY];
@@ -263,7 +270,7 @@ int main(int argc, char **argv)
int poll_timeout; int poll_timeout;
ret = server_init( ret = server_init(
&state, state,
argc, argc,
argv, argv,
poll_ctxs, poll_ctxs,
@@ -284,7 +291,7 @@ int main(int argc, char **argv)
#endif #endif
ret = server_tick( ret = server_tick(
&state, state,
poll_ctxs, poll_ctxs,
poll_array, poll_array,
POLL_CAPACITY, POLL_CAPACITY,
@@ -295,7 +302,8 @@ int main(int argc, char **argv)
return -1; return -1;
} }
server_free(&state); server_free(state);
free(state);
return 0; return 0;
} }