Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
149 lines (123 loc) · 5.03 KB
/
Copy pathMakefile
File metadata and controls
149 lines (123 loc) · 5.03 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
# pgshift — zero-downtime schema migration tooling for PostgreSQL.
#
# Two kinds of target, kept apart on purpose:
#
# * unit / lint / fuzz — offline, no database, no credentials. This is what CI
# runs on every push and what `make test` does. The pgwire codec, the SCRAM
# exchange, the plan validation and the latency maths are all exercised here.
#
# * cluster / integration / bench — need a real PostgreSQL primary and a
# streaming replica, brought up locally by scripts/cluster.sh. These are the
# targets that produce the measured numbers in the README, and they are never
# on the default path because they need something installed.
#
# The split is the honesty guarantee: the correctness suite runs with no server,
# and the numbers are reproduced against a real one with a single command.
GO ?= go
GOFLAGS ?=
BIN := bin
STAMP := $(shell date -u +%Y%m%d-%H%M%S)
RESULTS := results/run-$(STAMP)
# Cluster ports. 5514 primary, 5515 streaming replica.
PRIMARY_PORT ?= 5514
REPLICA_PORT ?= 5515
export PGSHIFT_PORT ?= $(PRIMARY_PORT)
export PGSHIFT_REPLICA_PORT ?= $(REPLICA_PORT)
export PGSHIFT_PASSWORD ?= pgshift
export PGSHIFT_TEST_PORT ?= $(PRIMARY_PORT)
export PGSHIFT_TEST_REPLICA_PORT ?= $(REPLICA_PORT)
export PGSHIFT_TEST_PASSWORD ?= pgshift
.PHONY: all
all: lint test build
.PHONY: build
build:
@mkdir -p $(BIN)
$(GO) build $(GOFLAGS) -o $(BIN)/pgshift ./cmd/pgshift
$(GO) build $(GOFLAGS) -o $(BIN)/shiftbench ./cmd/shiftbench
# Offline unit tests: no database. Everything with real SQL is skipped unless
# PGSHIFT_TEST_PORT points at a cluster.
.PHONY: test
test:
$(GO) test ./... -count=1
# The race detector is not optional for the workload harness and the migrator.
# The harness has many goroutines recording into shared latency recorders, and
# the benchmark drives a background replay-pause goroutine alongside a verifier
# on a separate connection. A data race there does not crash — it corrupts a
# reported number or desynchronises a connection, intermittently.
.PHONY: race
race:
$(GO) test ./... -race -count=1
.PHONY: lint
lint:
$(GO) vet ./...
@gofmt -l . | grep -v '^$$' && { echo "gofmt: files need formatting (run 'make fmt')"; exit 1; } || echo "gofmt: clean"
.PHONY: fmt
fmt:
gofmt -w .
.PHONY: cover
cover:
$(GO) test ./... -coverprofile=coverage.out -covermode=atomic
$(GO) tool cover -func=coverage.out | tail -30
# Fuzz the wire message reader: it parses a length off the network and allocates
# from it before reading a body, so a bounds bug there corrupts every subsequent
# message on the connection silently rather than failing loudly.
.PHONY: fuzz
fuzz:
$(GO) test ./internal/pgwire/ -run=Fuzz -fuzz=FuzzReadMessage -fuzztime=30s
# --- the local cluster (needs postgresql@16) --------------------------------
.PHONY: cluster-up
cluster-up:
@./scripts/cluster.sh up
.PHONY: cluster-down
cluster-down:
@./scripts/cluster.sh down
.PHONY: cluster-destroy
cluster-destroy:
@./scripts/cluster.sh destroy
.PHONY: cluster-status
cluster-status:
@./scripts/cluster.sh status
# Integration tests against the running cluster. Brings it up first.
.PHONY: test-integration
test-integration: cluster-up build
$(GO) test ./internal/migrate/ -count=1 -v
# --- measurements -----------------------------------------------------------
# Reproduces every number in the README into a fresh timestamped directory.
.PHONY: bench
bench: cluster-up build
$(BIN)/shiftbench -mode all -rows 2000000 -workers 16 -rps 3000 -out $(RESULTS)
@echo "results in $(RESULTS)"
# The baseline arm: a naive ALTER ... TYPE under load. Its write stall is what the
# tool exists to eliminate.
.PHONY: bench-control
bench-control: cluster-up build
$(BIN)/shiftbench -mode control -rows 2000000 -workers 16 -rps 3000 -out $(RESULTS)
# The full expand/backfill/verify/cutover cycle under the same load.
.PHONY: bench-treated
bench-treated: cluster-up build
$(BIN)/shiftbench -mode treated -rows 2000000 -workers 16 -rps 3000 -out $(RESULTS)
# The verification experiment: correct migration verifies clean under induced lag
# while single-pass cries wolf; three fault injections each get caught.
.PHONY: bench-faults
bench-faults: cluster-up build
$(BIN)/shiftbench -mode faults -out $(RESULTS)
# The replication-lag throttle, measured with lag deliberately induced.
.PHONY: bench-throttle
bench-throttle: cluster-up build
$(BIN)/shiftbench -mode throttle -rows 400000 -out $(RESULTS)
# Rollback from every phase, each verified from the catalog and the data.
.PHONY: bench-rollback
bench-rollback: cluster-up build
$(BIN)/shiftbench -mode rollback -out $(RESULTS)
# End-to-end self-check: a full cycle plus the rollback and fault drills against a
# real cluster, asserting from the catalog. This is the gate CI runs after
# bringing up its own Postgres.
.PHONY: selfcheck
selfcheck: cluster-up build
$(GO) test ./internal/migrate/ -count=1
$(BIN)/shiftbench -mode faults -out $(RESULTS)
$(BIN)/shiftbench -mode rollback -out $(RESULTS)
@echo "selfcheck passed"
.PHONY: clean
clean:
rm -rf $(BIN) coverage.out results/run-*