Viewing files at commit c44c91118a6cCommit detailsView latest

Browse files
suites/robustness/repro/concurrent-push-lost-ack.sh 38 lines · 2.7 KB · bash
1
#!/bin/bash
2
# P4 finding: two concurrent `oak push` to the same branch on loopback `oak serve`
3
# both exit 0; the independent server DB (sqlite3) shows one acknowledged commit
4
# is not an ancestor of the final branch head (lost acknowledged write).
5
# Usage: concurrent-push-lost-ack.sh <oak> <outdir> [trials]
6
set -u
7
OAK=$1; OUT=$2; TRIALS=${3:-5}
8
rm -rf "$OUT"; mkdir -p "$OUT/home" "$OUT/seed"
9
export HOME=$OUT/home OAK_NO_UPDATE_CHECK=1 OAK_API_KEY=p4tok OAK_AUTHOR=p4
10
unset OAK_REMOTE OAK_REPO OAK_TOKEN
11
PORT=$(python3 -c 'import socket;s=socket.socket();s.bind(("127.0.0.1",0));print(s.getsockname()[1])')
12
"$OAK" serve --dir "$OUT/srv" --port $PORT --token p4tok >"$OUT/serve.log" 2>&1 & SP=$!
13
trap 'kill $SP 2>/dev/null' EXIT
14
for i in $(seq 1 100); do curl -s -o /dev/null http://127.0.0.1:$PORT/api/capabilities && break; sleep 0.05; done
15
cd "$OUT/seed"; "$OAK" init . >/dev/null 2>&1; echo base > base.txt; "$OAK" commit >/dev/null 2>&1
16
"$OAK" push --repo p4/r -r http://127.0.0.1:$PORT >/dev/null 2>&1 || { echo seed push failed; exit 2; }
17
BR=$(sqlite3 .oak/oak.db "select value from metadata where key='current_branch'")
18
lost_total=0
19
for t in $(seq 1 $TRIALS); do
20
  rm -rf "$OUT/a" "$OUT/b"; "$OAK" pull >/dev/null 2>&1; cp -R "$OUT/seed" "$OUT/a"; cp -R "$OUT/seed" "$OUT/b"
21
  (cd "$OUT/a"; echo "a$t" > a$t.txt; "$OAK" commit >/dev/null 2>&1)
22
  (cd "$OUT/b"; echo "b$t" > b$t.txt; "$OAK" commit >/dev/null 2>&1)
23
  HA=$(sqlite3 "$OUT/a/.oak/oak.db" "select value from metadata where key='head'")
24
  HB=$(sqlite3 "$OUT/b/.oak/oak.db" "select value from metadata where key='head'")
25
  (cd "$OUT/a"; "$OAK" push >"$OUT/a.out" 2>&1; echo $? > "$OUT/a.rc") & PA=$!
26
  (cd "$OUT/b"; "$OAK" push >"$OUT/b.out" 2>&1; echo $? > "$OUT/b.rc") & PB=$!
27
  wait $PA $PB
28
  FINAL=$(sqlite3 "$OUT/srv/p4/r.oakdb" "select head_hash from branch_heads where branch_name='$BR'")
29
  # ancestors of FINAL via the independent server graph
30
  ANC=$(sqlite3 "$OUT/srv/p4/r.oakdb" "with recursive a(h) as (select '$FINAL' union select c.parent_hash from commits c join a on c.hash=a.h where c.parent_hash is not null union select c.merge_parent_hash from commits c join a on c.hash=a.h where c.merge_parent_hash is not null) select h from a")
31
  RA=$(cat "$OUT/a.rc"); RB=$(cat "$OUT/b.rc")
32
  inA=$(echo "$ANC" | grep -c "$HA"); inB=$(echo "$ANC" | grep -c "$HB")
33
  verdict=ok
34
  if [ "$RA" = 0 ] && [ "$inA" = 0 ]; then verdict=LOST_ACK_A; lost_total=$((lost_total+1)); fi
35
  if [ "$RB" = 0 ] && [ "$inB" = 0 ]; then verdict=LOST_ACK_B; lost_total=$((lost_total+1)); fi
36
  echo "trial=$t a_rc=$RA b_rc=$RB final=${FINAL:0:12} a=${HA:0:12}(in_final=$inA) b=${HB:0:12}(in_final=$inB) $verdict"
37
done
38
echo "lost_acknowledged_pushes=$lost_total/$TRIALS"