#!/bin/bash # Test: verify synapse_auto_compressor actually compresses bloated state # # Creates state groups WITHOUT edges (full snapshots), which is how # Synapse creates bloat in practice. The compressor should create # edges between them and convert full snapshots to deltas. set -euo pipefail SERVER="cctest.autonomic.zone" STACK_NAME="matrix-synapse_cctest_autonomic_zone" echo "=== Test: compress-state removes redundant state_groups_state rows ===" DB_CONTAINER=$(ssh "$SERVER" "docker ps --filter name=${STACK_NAME}_db --format '{{.ID}}'" | head -1) if [ -z "$DB_CONTAINER" ]; then echo "FAIL: Could not find db container" exit 1 fi echo "DB container: $DB_CONTAINER" run_sql() { local tmpfile=$(ssh "$SERVER" mktemp) echo "$1" | ssh "$SERVER" "cat > $tmpfile" ssh "$SERVER" "docker cp $tmpfile $DB_CONTAINER:/tmp/_query.sql && docker exec $DB_CONTAINER psql -U synapse -d synapse -t -A -f /tmp/_query.sql && rm -f $tmpfile" } ROOM_ID='!compress_test3:test.local' NUM_MEMBERS=20 NUM_GROUPS=200 # Full cleanup: all test data AND all compressor progress tables run_sql " DELETE FROM state_groups_state WHERE room_id LIKE '!compress_test%'; DELETE FROM state_group_edges WHERE state_group IN (SELECT id FROM state_groups WHERE room_id LIKE '!compress_test%'); DELETE FROM state_groups WHERE room_id LIKE '!compress_test%'; TRUNCATE state_compressor_state; TRUNCATE state_compressor_progress; TRUNCATE state_compressor_total_progress; " > /dev/null 2>&1 || true MAX_SG=$(run_sql "SELECT COALESCE(MAX(id), 0) FROM state_groups;") echo "Current max state_group id: $MAX_SG" BASE=$((MAX_SG + 1000)) echo "Generating $NUM_GROUPS full-snapshot state groups (no edges) with $NUM_MEMBERS members..." SQL_FILE=$(mktemp /tmp/compress_test_XXXXXX.sql) echo "BEGIN;" > "$SQL_FILE" declare -A CURRENT_EVENT for m in $(seq 1 $NUM_MEMBERS); do CURRENT_EVENT[$m]="mem_${m}_v0" done for g in $(seq 0 $((NUM_GROUPS - 1))); do SG_ID=$((BASE + g)) echo "INSERT INTO state_groups (id, room_id, event_id) VALUES ($SG_ID, '$ROOM_ID', 'ev_g${g}');" >> "$SQL_FILE" # NO edges — each group is a standalone full snapshot # One member changes per group CHANGING=$(( (g % NUM_MEMBERS) + 1 )) CURRENT_EVENT[$CHANGING]="mem_${CHANGING}_v${g}" # Store ALL state in every group for m in $(seq 1 $NUM_MEMBERS); do EV="${CURRENT_EVENT[$m]}" echo "INSERT INTO state_groups_state (state_group, room_id, type, state_key, event_id) VALUES ($SG_ID, '$ROOM_ID', 'm.room.member', '@user${m}:test.local', '${EV}');" >> "$SQL_FILE" done echo "INSERT INTO state_groups_state (state_group, room_id, type, state_key, event_id) VALUES ($SG_ID, '$ROOM_ID', 'm.room.create', '', 'create_ev');" >> "$SQL_FILE" echo "INSERT INTO state_groups_state (state_group, room_id, type, state_key, event_id) VALUES ($SG_ID, '$ROOM_ID', 'm.room.name', '', 'name_ev');" >> "$SQL_FILE" echo "INSERT INTO state_groups_state (state_group, room_id, type, state_key, event_id) VALUES ($SG_ID, '$ROOM_ID', 'm.room.topic', '', 'topic_ev');" >> "$SQL_FILE" done echo "COMMIT;" >> "$SQL_FILE" echo "Generated $(wc -l < "$SQL_FILE") lines of SQL" echo "Inserting test data..." scp -q "$SQL_FILE" "$SERVER:/tmp/compress_test.sql" ssh "$SERVER" "docker cp /tmp/compress_test.sql $DB_CONTAINER:/tmp/compress_test.sql" ssh "$SERVER" "docker exec $DB_CONTAINER psql -U synapse -d synapse -f /tmp/compress_test.sql" > /dev/null 2>&1 echo "Insert complete." rm -f "$SQL_FILE" ROWS_AFTER_INSERT=$(run_sql "SELECT COUNT(*) FROM state_groups_state WHERE room_id = '$ROOM_ID';") EDGES_BEFORE=$(run_sql "SELECT COUNT(*) FROM state_group_edges WHERE state_group IN (SELECT id FROM state_groups WHERE room_id = '$ROOM_ID');") echo "Rows in state_groups_state: $ROWS_AFTER_INSERT" echo "Edges in state_group_edges: $EDGES_BEFORE" echo "" echo "Running synapse_auto_compressor..." COMPRESS_CONTAINER=$(ssh "$SERVER" "docker ps --filter name=${STACK_NAME}_compress-state --format '{{.ID}}'" | head -1) if [ -z "$COMPRESS_CONTAINER" ]; then echo "FAIL: Could not find compress-state container" exit 1 fi DB_PASS=$(ssh "$SERVER" "docker exec $DB_CONTAINER cat /run/secrets/db_password") COMPRESS_OUTPUT=$(ssh "$SERVER" "docker exec $COMPRESS_CONTAINER /build/synapse_auto_compressor \ -p 'postgresql://synapse:${DB_PASS}@db:5432/synapse' \ -c 100 -n 10 2>&1") || true echo "$COMPRESS_OUTPUT" ROWS_AFTER_COMPRESS=$(run_sql "SELECT COUNT(*) FROM state_groups_state WHERE room_id = '$ROOM_ID';") EDGES_AFTER=$(run_sql "SELECT COUNT(*) FROM state_group_edges WHERE state_group IN (SELECT id FROM state_groups WHERE room_id = '$ROOM_ID');") echo "" echo "=== Results ===" echo "Rows BEFORE compression: $ROWS_AFTER_INSERT" echo "Rows AFTER compression: $ROWS_AFTER_COMPRESS" SAVED=$((ROWS_AFTER_INSERT - ROWS_AFTER_COMPRESS)) echo "Rows saved: $SAVED" echo "Edges BEFORE: $EDGES_BEFORE" echo "Edges AFTER: $EDGES_AFTER" if [ "$SAVED" -gt 0 ]; then PCT=$((SAVED * 100 / ROWS_AFTER_INSERT)) echo "Compression ratio: ${PCT}%" echo "" echo "PASS: Compressor removed $SAVED redundant rows (${PCT}% reduction)" else echo "" echo "FAIL: Compressor did not remove any rows" exit 1 fi # Clean up echo "" echo "Cleaning up test data..." run_sql "DELETE FROM state_groups_state WHERE room_id = '$ROOM_ID'; DELETE FROM state_group_edges WHERE state_group IN (SELECT id FROM state_groups WHERE room_id = '$ROOM_ID'); DELETE FROM state_groups WHERE room_id = '$ROOM_ID';" > /dev/null ssh "$SERVER" "rm -f /tmp/compress_test.sql" echo "Cleanup complete."