Skip to content

Commit 5b02be6

Browse files
author
Palash Chauhan
committed
changes
1 parent efab533 commit 5b02be6

9 files changed

Lines changed: 92 additions & 16 deletions

File tree

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,14 @@ Skip steps 1-2 above with the bundled Docker cluster. From a fresh clone:
7777
```bash
7878
# 1. Bring up the full stack at the versions pinned in pom.xml and BLOCK
7979
# until every container reports healthy (REST is ~30-60s on cold start).
80-
# First time: ~8-12 min total; subsequent runs are cached.
80+
# First time: ~8-12 min total -- most of that is Maven downloading
81+
# ~1.5 GB of dependencies into the BuildKit cache mount. Subsequent
82+
# runs reuse the cache and rebuild in seconds.
8183
docker compose -f docker/docker-compose.yml up -d --build --wait
8284

8385
# 2. Validate it works end-to-end (CRUD + UpdateItem + BatchWriteItem + streams).
8486
bash docker/scripts/smoke.sh
85-
# -> "Result: 20 checks PASSED across 18 API calls"
87+
# -> "Result: 21 checks PASSED across 18 API calls"
8688

8789
# 3. Use it. The DynamoDB-compatible endpoint is at http://localhost:8842 .
8890
# Point any AWS SDK at it (Java/Python/Node.js snippets in

docker/Dockerfile.phoenix-adapters

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,16 @@ RUN --mount=type=cache,target=/root/.m2 \
3434
clean package
3535

3636
RUN set -eux; \
37-
tarball=$(ls phoenix-ddb-assembly/target/phoenix-adapters-*-bin.tar.gz | head -n1); \
38-
cp "${tarball}" /tmp/phoenix-adapters-bin.tar.gz
37+
# If the assembly module ever ships an additional *-bin.tar.gz (e.g.
38+
# with a classifier), fail loudly rather than silently picking one.
39+
count=$(find phoenix-ddb-assembly/target -maxdepth 1 -type f -name 'phoenix-adapters-*-bin.tar.gz' | wc -l); \
40+
if [ "$count" -ne 1 ]; then \
41+
echo "Expected exactly one phoenix-adapters-*-bin.tar.gz, found $count:" >&2; \
42+
find phoenix-ddb-assembly/target -maxdepth 1 -type f -name 'phoenix-adapters-*-bin.tar.gz' >&2; \
43+
exit 1; \
44+
fi; \
45+
tarball=$(find phoenix-ddb-assembly/target -maxdepth 1 -type f -name 'phoenix-adapters-*-bin.tar.gz'); \
46+
cp "$tarball" /tmp/phoenix-adapters-bin.tar.gz
3947

4048
FROM eclipse-temurin:8-jdk-jammy
4149

docker/README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,14 @@ From the **project root**:
4848
# 1. Bring up the full stack (ZK + HDFS + HBase+Phoenix + REST) and BLOCK
4949
# until every service reports healthy (REST takes ~30-60s on a cold
5050
# start because Phoenix has to bootstrap SYSTEM.* tables).
51-
# First time: ~8-12 min (pulls upstream images + builds HBase/Phoenix + REST).
52-
# Subsequent runs: cached.
51+
# First time: ~8-12 min -- most of that is Maven downloading ~1.5 GB
52+
# of dependencies into the BuildKit cache mount; subsequent runs reuse
53+
# the cache and rebuild in seconds.
5354
docker compose -f docker/docker-compose.yml up -d --build --wait
5455

5556
# 2. Validate it works end-to-end (CRUD + UpdateItem + BatchWriteItem + streams).
5657
bash docker/scripts/smoke.sh
57-
# -> "Result: 20 checks PASSED across 18 API calls"
58+
# -> "Result: 21 checks PASSED across 18 API calls"
5859

5960
# 3. Use it. The DynamoDB-compatible REST endpoint is at http://localhost:8842 .
6061
# Point any AWS SDK at it (Java/Python/Node.js snippets in
@@ -91,7 +92,7 @@ Inter-container traffic still uses the standard ports.
9192
### Bring up just the cluster (no REST)
9293

9394
```bash
94-
docker compose -f docker/docker-compose.yml up -d --build \
95+
docker compose -f docker/docker-compose.yml up -d --build --wait \
9596
zookeeper namenode datanode hbase-master hbase-regionserver
9697
```
9798

@@ -224,6 +225,7 @@ HBase data persists across full `down`/`up` cycles.
224225
| Added a Maven dep to `phoenix-ddb-rest/pom.xml` | `--build phoenix-adapters-rest`. New dep downloads once; cache warms after. |
225226
| Clean slate | `docker compose ... down -v` then `up -d --build`. |
226227
| Code doesn't seem picked up | You ran `restart` instead of `up --build`. `restart` does not rebuild. |
228+
| Stack left running for days / many smoke iterations | HBase + REST logs grow unbounded inside the containers. `down -v` periodically to reclaim disk. |
227229

228230
### Pre-PR checklist
229231

@@ -240,7 +242,7 @@ bash docker/scripts/smoke.sh
240242
docker compose -f docker/docker-compose.yml down -v
241243
```
242244

243-
If `smoke.sh` finishes with `Result: 20 checks PASSED across 18 API calls`,
245+
If `smoke.sh` finishes with `Result: 21 checks PASSED across 18 API calls`,
244246
your change is wire-compatible end to end through Phoenix on dockerized
245247
HBase across CRUD, batch, and the change-stream chain.
246248

@@ -277,7 +279,7 @@ RPC controller:
277279
| `hbase.regionserver.wal.codec` | `…IndexedWALEditCodec` |
278280
| `hbase.region.server.rpc.scheduler.factory.class` | `…PhoenixRpcSchedulerFactory` |
279281
| `hbase.rpc.controllerfactory.class` | `…ServerRpcControllerFactory` |
280-
| `phoenix.task.handling.interval.ms` | `10` |
282+
| `phoenix.task.handling.interval.ms` | `1000` |
281283
| `phoenix.task.handling.initial.delay.ms` | `1` |
282284

283285
`phoenix-server-hbase-2.5-5.3.1.jar` is copied into `${HBASE_HOME}/lib/` so

docker/conf/hbase/hbase-env.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ export HBASE_HEAPSIZE=1G
99
export HBASE_OFFHEAPSIZE=256m
1010

1111
# Strip JDK11-specific GC flags HBase ships with; we run on JDK8.
12+
# This intentionally REPLACES the upstream value (rather than appending),
13+
# so any future upstream flag drops out of the container -- add new flags
14+
# to this list directly instead of re-deriving from upstream's HBASE_OPTS.
1215
export HBASE_OPTS="-XX:+UseG1GC -XX:+UnlockExperimentalVMOptions"
1316
export HBASE_MASTER_OPTS="${HBASE_OPTS} -Xms256m"
1417
export HBASE_REGIONSERVER_OPTS="${HBASE_OPTS} -Xms512m"

docker/conf/hbase/hbase-site.xml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@
1717
<name>hbase.zookeeper.property.clientPort</name>
1818
<value>2181</value>
1919
</property>
20+
<!--
21+
Dev-only: disables the HDFS hflush/hsync capability check so the
22+
single-replica datanode in this stack can serve HBase WAL writes.
23+
Do NOT copy this property into a production hbase-site.xml.
24+
-->
2025
<property>
2126
<name>hbase.unsafe.stream.capability.enforce</name>
2227
<value>false</value>
@@ -47,9 +52,15 @@
4752
<name>hbase.rpc.controllerfactory.class</name>
4853
<value>org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory</value>
4954
</property>
55+
<!--
56+
Phoenix default is 60000 ms; we cut it to 1000 ms so dev-cluster
57+
background tasks (index state transitions, dropped-table GC, etc.)
58+
run quickly enough to keep iteration tight, without the laptop
59+
CPU cost of a ~10 ms poll loop.
60+
-->
5061
<property>
5162
<name>phoenix.task.handling.interval.ms</name>
52-
<value>10</value>
63+
<value>1000</value>
5364
</property>
5465
<property>
5566
<name>phoenix.task.handling.initial.delay.ms</name>

docker/conf/phoenix-adapters/hbase-site.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
</property>
1313
<property>
1414
<name>phoenix.task.handling.interval.ms</name>
15-
<value>10</value>
15+
<value>1000</value>
1616
</property>
1717
<property>
1818
<name>phoenix.task.handling.initial.delay.ms</name>

docker/docker-compose.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77

88
name: phoenix-adapters
99

10+
# The container_name keys below pin each service to a fixed name (phx-*).
11+
# Combined with the fixed host ports (8842/9870/12181/etc.), this means
12+
# only one copy of the stack can run on a workstation at a time. That's
13+
# intentional given the host-port collisions; if you need parallel stacks,
14+
# drop the container_name keys AND change the host-port mappings.
1015
services:
1116

1217
zookeeper:

docker/scripts/phoenix-adapters-entrypoint.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,26 @@ set -euo pipefail
33

44
log() { echo "[phoenix-adapters][$(date -u +%H:%M:%S)] $*"; }
55

6+
# Guard against accidental reintroduction of the 3.4.x hadoop client jars.
7+
# Dockerfile.phoenix-adapters strips them because they reference
8+
# org.apache.hadoop.fs.WithErasureCoding (only present in hadoop-common
9+
# 3.4+), which poisons the client JVM via FileSystem ServiceLoader the
10+
# first time HBase returns a remote exception. If anyone re-adds them,
11+
# fail fast with a clear pointer instead of dying mid-bootstrap.
12+
shopt -s nullglob
13+
stray=( "${PHOENIX_ADAPTERS_HOME}/lib/hadoop-hdfs-"*.jar \
14+
"${PHOENIX_ADAPTERS_HOME}/lib/hadoop-hdfs-client-"*.jar \
15+
"${PHOENIX_ADAPTERS_HOME}/lib/hadoop-yarn-"*.jar \
16+
"${PHOENIX_ADAPTERS_HOME}/lib/hadoop-mapreduce-client-"*.jar \
17+
"${PHOENIX_ADAPTERS_HOME}/lib/hadoop-distcp-"*.jar )
18+
shopt -u nullglob
19+
if [[ ${#stray[@]} -gt 0 ]]; then
20+
log "ERROR: assembly contains hadoop 3.4.x jars that must be stripped:"
21+
for j in "${stray[@]}"; do log " - ${j##*/}"; done
22+
log "See the 'rm -f hadoop-hdfs-*' block in docker/Dockerfile.phoenix-adapters."
23+
exit 1
24+
fi
25+
626
wait_for() {
727
local host="$1" port="$2"
828
log "Waiting for ${host}:${port} ..."

docker/scripts/smoke.sh

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,22 @@ show_json() {
6565
LAST_RESP=""
6666

6767
# Prints request + response visually and stashes the raw JSON in LAST_RESP.
68+
# Aborts immediately if the response is a DDB error envelope (has __type),
69+
# so per-step assertions don't have to translate confusing "expected X got
70+
# null" failures back into the underlying Phoenix error.
6871
ddb() {
6972
local action="$1" body="$2"
7073
show_json "request " "$body"
7174
LAST_RESP=$(curl -sS -X POST "$URL/" -H "$CT" -H "$TARGET.$action" -d "$body")
7275
show_json "response" "$LAST_RESP"
76+
if printf '%s' "$LAST_RESP" | jq -e 'type == "object" and has("__type")' >/dev/null 2>&1; then
77+
local err_type err_msg
78+
err_type=$(printf '%s' "$LAST_RESP" | jq -r '.__type // "?"')
79+
err_msg=$(printf '%s' "$LAST_RESP" | jq -r '.Message // .message // ""')
80+
printf " ${RED}${RESET} %s returned error ${B}%s${RESET}: %s\n" \
81+
"$action" "$err_type" "$err_msg" >&2
82+
exit 1
83+
fi
7384
}
7485

7586
assert_eq() {
@@ -97,7 +108,10 @@ assert_nonempty() {
97108

98109
assert_ge() {
99110
local label="$1" actual="$2" threshold="$3"
100-
if [[ "$actual" -ge "$threshold" ]]; then
111+
# Coerce non-numeric (null, empty, "true", etc.) to 0 so the arithmetic
112+
# comparison can't abort the script with "integer expression expected".
113+
[[ "$actual" =~ ^-?[0-9]+$ ]] || actual=0
114+
if (( actual >= threshold )); then
101115
printf " ${GREEN}${RESET} %s ${B}>=${RESET} %s (got %s)\n" "$label" "$threshold" "$actual"
102116
PASS=$((PASS + 1))
103117
else
@@ -280,7 +294,7 @@ iter=$(jq -r '.ShardIterator // empty' <<<"$LAST_RESP")
280294
assert_nonempty "ShardIterator" "$iter"
281295

282296
step "GetRecords (drain pages until empty)"
283-
total=0; pages=0; seen_keys=""
297+
total=0; pages=0; seen_keys=""; advanced=false
284298
while [[ -n "$iter" && "$iter" != "null" && $pages -lt 10 ]]; do
285299
pages=$((pages + 1))
286300
ddb GetRecords "{\"ShardIterator\":\"$iter\"}"
@@ -290,16 +304,27 @@ while [[ -n "$iter" && "$iter" != "null" && $pages -lt 10 ]]; do
290304
total=$((total + n))
291305
printf " ${DIM}page %d: %d record(s) keys=[%s]${RESET}\n" "$pages" "$n" "$keys"
292306
next=$(jq -r '.NextShardIterator // empty' <<<"$LAST_RESP")
293-
if [[ "$next" == "$iter" || -z "$next" || "$next" == "null" ]]; then
307+
# Iterator stuck-at-position guard: if NextShardIterator equals the
308+
# current one across consecutive empty pages, the stream isn't actually
309+
# being consumed, so further pages would just spin.
310+
if [[ -z "$next" || "$next" == "null" || "$next" == "$iter" ]]; then
294311
break
295312
fi
313+
advanced=true
296314
iter="$next"
297315
[[ $n -eq 0 ]] && break
298316
done
299317
printf " ${DIM}total records: %d keys=[%s]${RESET}\n" "$total" "$seen_keys"
300318
# Expect >= 4 mutations (PutItem-a, UpdateItem-a, PutItem-b, DeleteItem-b) plus
301-
# 3 from the batch (delete-a, put-c, put-d).
319+
# 3 from the batch (delete-a, put-c, put-d) -- 7 total in steady state.
302320
assert_ge "stream record count" "$total" "4"
321+
if $advanced; then
322+
printf " ${GREEN}${RESET} ShardIterator advanced across pages\n"
323+
PASS=$((PASS + 1))
324+
else
325+
printf " ${RED}${RESET} ShardIterator never advanced; stream appears stuck\n" >&2
326+
exit 1
327+
fi
303328

304329
step "DeleteTable (cleanup)"
305330
ddb DeleteTable "{\"TableName\":\"$TBL\"}"

0 commit comments

Comments
 (0)