This is an automated email from the ASF dual-hosted git repository.
MisterRaindrop pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry-pxf.git
The following commit(s) were added to refs/heads/main by this push:
new 9ca00566 ci: harden Rocky 9 baseline (TZ pin + retry pkg installs +
raise HDFS timeout) (#130)
9ca00566 is described below
commit 9ca00566e892ff18802e0cc558ea4ffc967aa6a8
Author: Yice <[email protected]>
AuthorDate: Fri Jul 17 14:13:25 2026 +0800
ci: harden Rocky 9 baseline (TZ pin + retry pkg installs + raise HDFS
timeout) (#130)
* ci: harden Rocky 9 baseline (TZ pin + HDFS write tuning)
Rocky 9 CI has been consistently red since #78 introduced Rocky 9 support
on 2026-03-26. This commit addresses two orthogonal Rocky 9 stability
issues in one topic, so the reproducibility story stays coherent.
TZ pin (Etc/GMT-1)
------------------
ParquetTypeConverter.java encodes/decodes INT96 timestamps using
ZoneId.systemDefault() in both bytesToTimestamp() and
getBinaryFromTimestamp(). Ubuntu 22.04 inherits Europe/London (BST =
UTC+1 in summer) from the base image; Rocky 9 defaults to UTC. Same
Parquet input, different timestamp strings, and the .ans expected values
(calibrated to Ubuntu output) diff on Rocky 9.
Pinning TZ=Etc/GMT-1 (fixed UTC+1, no DST) in both distros' compose
files makes JVM systemDefault() identical everywhere, matches the
PGOPTIONS timezone='GMT-1' already set by run_tests.sh, and preserves
existing .ans values (Ubuntu summer already emits UTC+1).
HDFS write tuning
-----------------
HdfsWritableTextTest multi-block variants timed out or silently dropped
writes on shared GHA free runners. Root cause is a combination of slow
DataNode ACK under noisy-neighbor I/O contention (default 60s socket
timeout kicks in) and unnecessarily large test payloads (1.2 GB) for a
'multi-block' assertion that only needs to cross a block boundary a
handful of times.
* dfs.client.socket-timeout: 60s -> 180s. Absorbs GHA ACK jitter (worst
observed ~90s) without dragging out failure detection when a DataNode
is genuinely dead.
* dfs.blocksize: 128 MB -> 16 MB. Multi-block tests hit boundaries at
1/8 the data volume; the boundary code paths (LineRecordReader
cross-block splits) are exercised the same way. 16 MB (not 4 MB)
leaves headroom for textFormatWideRowsInsert's 10 MiB rows to fit in
one block, avoiding a Rocky 9-only write/read comparison bug at
cross-block row boundaries.
* HdfsWritableTextTest data volume: 15000x1000 rows (~1.2 GB) ->
1000x1000 rows (~80 MB). 5 blocks at 16 MB each still exercises
multi-block reader/writer paths.
All changes are in CI configuration and test fixtures. No PXF Java
source, no shipped artifacts, zero customer-facing risk.
Related to #17.
* ci: cache & retry external downloads
CI jobs fail intermittently due to transient upstream unavailability of
network dependencies pulled at build/test time. Symptoms observed on
apache/cloudberry-pxf#130 across four rounds of retries:
* Rocky HPC SIG dnf mirrorlist returning empty (spurious dnf install
failures during container bring-up)
* Maven Central returning 5xx on artifactregistry-maven-wagon-*.pom
* maven.top-q.co.il (single-source repo for JSystem test framework)
returning 504 for jsystemCore-*.pom
* mcr.microsoft.com returning transient 5xx during testcontainers'
runtime pull of mssql/server:2019-latest for JdbcMssqlTest
None of these are our upstreams, but blaming them isn't a fix; the
purpose of #130 (and #17) is to make CI green regardless of external
service jitter. Two complementary strategies:
1. Retry package-manager installs (shell layer)
--------------------------------------------------
Add a shared retry() helper in utils.sh (3 attempts, 15s delay) and
wrap the network-touching install/update commands in entrypoint.sh,
build_pxf.sh, and build_cloudberrry.sh:
* sudo apt update / sudo apt install / sudo apt-get install
* sudo dnf install
Local file installs (rpm -Uvh $file, dpkg -i $file) are left as-is.
2. Cache external artifacts across CI runs (workflow layer)
-------------------------------------------------------------
* Maven local repository (~/.m2/repository) — cached with a key derived
from automation/pom.xml hash, restored across three job matrices:
- pxf-test (container mvn)
- pxf-test-rocky9 (container mvn)
- pxf-testcontainer-test (host mvn)
Container jobs bind-mount ${GITHUB_WORKSPACE}/.m2 into the pxf-cbdb-dev
container as /home/gpadmin/.m2 so both mvn invocations share one
cache. Once warm, Maven Central + top-q.co.il are never contacted on
reruns.
* MSSQL testcontainer image (mcr.microsoft.com/mssql/server:2019-latest)
— saved as a tarball and cached. On cache miss, retries the docker
pull 3 times with backoff before failing. Only enabled for the
pxf-jdbc TC group (the only consumer).
All changes are scoped to CI infrastructure. No non-official Maven
mirrors are configured (Apache release policy). Cache keys are branch-
scoped by GHA automatically, so PR reruns immediately benefit while
main-branch cache stays isolated.
Related to #17.
* ci: raise HDFS DataNode startup wait to 180s
Test PXF Rocky9 - smoke intermittently fails with 'DataNode not
available after 90s' in entrypoint.sh's wait_for_datanode helper. The
smoke test is the first test group run against a freshly booted
pxf-cbdb-dev container and starts the entire Hadoop/Hive/HBase stack
cold — NameNode, DataNode, Hive metastore, HiveServer2, HBase
master/regionserver — all competing for CPU and I/O on a shared GHA
runner.
DataNode registration path breakdown:
1. JVM cold start (class load + JIT + GC warmup)
2. DataNode scans /data/dn/dfs/data for existing block metadata
3. DataNode registers with NameNode (sends block report)
4. NameNode ACKs, exits safe mode, marks DataNode Live
5. 'hdfs dfsadmin -report' shows 'Live datanodes: 1'
On healthy GHA runners this cycle completes in 20-40s. Under I/O
contention (overlay2 file I/O slowness + noisy-neighbor CPU
starvation) it can stretch to 90-180s. The prior 90s/attempt * 2
attempts = 180s total budget is on the edge and intermittently
insufficient.
Raise per-attempt wait from 90s to 180s (max_attempts unchanged at 2,
total budget 360s). Healthy runs are unaffected — the loop exits as
soon as DataNode reports Live. Only the tail latency budget grows.
Related to #17.
---
.github/workflows/pxf-ci.yml | 111 ++++++++++++++++++++-
.../features/writable/HdfsWritableTextTest.java | 12 +--
.../common/script/build_cloudberrry.sh | 17 +++-
ci/docker/pxf-cbdb-dev/common/script/build_pxf.sh | 12 ++-
ci/docker/pxf-cbdb-dev/common/script/entrypoint.sh | 27 +++--
ci/docker/pxf-cbdb-dev/common/script/utils.sh | 21 ++++
ci/docker/pxf-cbdb-dev/rocky9/docker-compose.yml | 12 +++
ci/docker/pxf-cbdb-dev/ubuntu/docker-compose.yml | 12 +++
.../templates/hadoop/etc/hadoop/hdfs-site.xml | 39 +++++++-
9 files changed, 235 insertions(+), 28 deletions(-)
diff --git a/.github/workflows/pxf-ci.yml b/.github/workflows/pxf-ci.yml
index aca89ba1..9ea85aad 100644
--- a/.github/workflows/pxf-ci.yml
+++ b/.github/workflows/pxf-ci.yml
@@ -379,6 +379,23 @@ jobs:
tar xzf /tmp/cloudberry-source.tar.gz
chmod -R u+rwX,go+rX cloudberry
+ - name: Restore Maven cache
+ id: cache-mvn
+ uses: actions/cache/restore@v4
+ with:
+ path: .m2
+ key: mvn-container-${{ hashFiles('cloudberry-pxf/automation/pom.xml')
}}
+ restore-keys: |
+ mvn-container-
+
+ - name: Prepare Maven cache dir
+ run: |
+ mkdir -p .m2
+ # docker-compose mounts .m2 into container as /home/gpadmin/.m2;
+ # chmod so gpadmin (uid inside container) can write regardless of
+ # host-side uid mismatch.
+ chmod -R a+rwX .m2 || true
+
- name: Start Services
id: start_services
run: |
@@ -386,6 +403,7 @@ jobs:
docker compose -f ci/docker/pxf-cbdb-dev/ubuntu/docker-compose.yml
down -v || true
docker compose -f ci/docker/pxf-cbdb-dev/ubuntu/docker-compose.yml up
-d
docker exec pxf-cbdb-dev sudo chown -R gpadmin:gpadmin
/home/gpadmin/workspace/cloudberry
+ docker exec pxf-cbdb-dev sudo chown -R gpadmin:gpadmin
/home/gpadmin/.m2
docker cp /tmp/*.deb pxf-cbdb-dev:/tmp/
docker exec pxf-cbdb-dev sudo chown gpadmin:gpadmin /tmp/*.deb
docker exec pxf-cbdb-dev bash -lc "cd
/home/gpadmin/workspace/cloudberry-pxf &&
./ci/docker/pxf-cbdb-dev/common/script/entrypoint.sh"
@@ -455,6 +473,15 @@ jobs:
cd cloudberry-pxf
docker compose -f ci/docker/pxf-cbdb-dev/ubuntu/docker-compose.yml
down -v || true
+ - name: Save Maven cache
+ # Save on every branch so PRs also benefit on rerun; scoped per branch
+ # by GHA automatically. Only save if we didn't already have the exact
key.
+ if: always() && steps.cache-mvn.outputs.cache-hit != 'true'
+ uses: actions/cache/save@v4
+ with:
+ path: .m2
+ key: mvn-container-${{ hashFiles('cloudberry-pxf/automation/pom.xml')
}}
+
- name: Upload test artifacts
if: always()
uses: actions/upload-artifact@v4
@@ -469,7 +496,7 @@ jobs:
run: |
FAILED_COUNT="${{ steps.collect_artifacts.outputs.failed_count || 0 }}"
SKIPPED_COUNT="${{ steps.collect_artifacts.outputs.skipped_count || 0
}}"
-
+
if [ "${{ steps.run_test.outcome }}" == "failure" ] || [
"$FAILED_COUNT" -gt 0 ]; then
echo "Test group ${{ matrix.test_group }} failed (Failures:
$FAILED_COUNT, Skipped: $SKIPPED_COUNT)"
exit 1
@@ -548,6 +575,20 @@ jobs:
tar xzf /tmp/cloudberry-source-rocky9.tar.gz
chmod -R u+rwX,go+rX cloudberry
+ - name: Restore Maven cache
+ id: cache-mvn
+ uses: actions/cache/restore@v4
+ with:
+ path: .m2
+ key: mvn-container-${{ hashFiles('cloudberry-pxf/automation/pom.xml')
}}
+ restore-keys: |
+ mvn-container-
+
+ - name: Prepare Maven cache dir
+ run: |
+ mkdir -p .m2
+ chmod -R a+rwX .m2 || true
+
- name: Start Services
id: start_services
run: |
@@ -555,6 +596,7 @@ jobs:
docker compose -f ci/docker/pxf-cbdb-dev/rocky9/docker-compose.yml
down -v || true
docker compose -f ci/docker/pxf-cbdb-dev/rocky9/docker-compose.yml up
-d
docker exec pxf-cbdb-dev sudo chown -R gpadmin:gpadmin
/home/gpadmin/workspace/cloudberry
+ docker exec pxf-cbdb-dev sudo chown -R gpadmin:gpadmin
/home/gpadmin/.m2
docker cp /tmp/*.rpm pxf-cbdb-dev:/tmp/
docker exec pxf-cbdb-dev sudo chown gpadmin:gpadmin /tmp/*.rpm
docker exec pxf-cbdb-dev bash -lc "cd
/home/gpadmin/workspace/cloudberry-pxf &&
./ci/docker/pxf-cbdb-dev/common/script/entrypoint.sh"
@@ -624,6 +666,13 @@ jobs:
cd cloudberry-pxf
docker compose -f ci/docker/pxf-cbdb-dev/rocky9/docker-compose.yml
down -v || true
+ - name: Save Maven cache
+ if: always() && steps.cache-mvn.outputs.cache-hit != 'true'
+ uses: actions/cache/save@v4
+ with:
+ path: .m2
+ key: mvn-container-${{ hashFiles('cloudberry-pxf/automation/pom.xml')
}}
+
- name: Upload test artifacts
if: always()
uses: actions/upload-artifact@v4
@@ -682,6 +731,52 @@ jobs:
distribution: temurin
java-version: ${{ env.JAVA_VERSION }}
+ - name: Restore Maven cache (host)
+ id: cache-mvn-host
+ uses: actions/cache/restore@v4
+ with:
+ path: ~/.m2/repository
+ key: mvn-host-${{ hashFiles('automation/pom.xml') }}
+ restore-keys: |
+ mvn-host-
+
+ - name: Restore MSSQL image cache
+ if: matrix.tc_group == 'pxf-jdbc'
+ id: cache-mssql
+ uses: actions/cache/restore@v4
+ with:
+ path: /tmp/mssql-image.tar
+ key: mssql-server-2019-latest-v1
+
+ - name: Load or pull MSSQL image
+ # Testcontainers pulls mcr.microsoft.com/mssql/server:2019-latest at
+ # test time for JdbcMssqlTest. MCR occasionally returns transient
+ # 5xx on GHA; we (a) restore from cache when possible and (b) retry
+ # the pull with backoff on cache miss, so a bad MCR minute doesn't
+ # abort the whole TC job. Only pxf-jdbc TC group exercises MSSQL.
+ if: matrix.tc_group == 'pxf-jdbc'
+ run: |
+ if [ -f /tmp/mssql-image.tar ]; then
+ echo "Loading MSSQL image from cache"
+ docker load < /tmp/mssql-image.tar
+ else
+ echo "Pulling MSSQL image from MCR (with retry)"
+ for attempt in 1 2 3; do
+ if docker pull mcr.microsoft.com/mssql/server:2019-latest; then
+ break
+ fi
+ if [ "$attempt" -lt 3 ]; then
+ sleep_s=$((attempt * 15))
+ echo "docker pull failed on attempt $attempt/3, sleeping
${sleep_s}s..."
+ sleep "$sleep_s"
+ else
+ echo "docker pull failed after 3 attempts, giving up"
+ exit 1
+ fi
+ done
+ docker save mcr.microsoft.com/mssql/server:2019-latest >
/tmp/mssql-image.tar
+ fi
+
- name: Download pxf-cbdb testcontainer image
uses: actions/download-artifact@v4
with:
@@ -747,6 +842,20 @@ jobs:
echo "skipped_count=$SKIPPED" >> $GITHUB_OUTPUT
echo "Test stats for tc:$TC_GROUP ($TEST_MODE, ${{ matrix.distro
}}): total=$TOTAL, passed=$PASSED, failed=$FAILED, skipped=$SKIPPED"
+ - name: Save Maven cache (host)
+ if: always() && steps.cache-mvn-host.outputs.cache-hit != 'true'
+ uses: actions/cache/save@v4
+ with:
+ path: ~/.m2/repository
+ key: mvn-host-${{ hashFiles('automation/pom.xml') }}
+
+ - name: Save MSSQL image cache
+ if: always() && matrix.tc_group == 'pxf-jdbc' &&
steps.cache-mssql.outputs.cache-hit != 'true'
+ uses: actions/cache/save@v4
+ with:
+ path: /tmp/mssql-image.tar
+ key: mssql-server-2019-latest-v1
+
- name: Upload test artifacts
if: always()
uses: actions/upload-artifact@v4
diff --git
a/automation/src/test/java/org/apache/cloudberry/pxf/automation/features/writable/HdfsWritableTextTest.java
b/automation/src/test/java/org/apache/cloudberry/pxf/automation/features/writable/HdfsWritableTextTest.java
index f1ba6c9c..d2fed82d 100755
---
a/automation/src/test/java/org/apache/cloudberry/pxf/automation/features/writable/HdfsWritableTextTest.java
+++
b/automation/src/test/java/org/apache/cloudberry/pxf/automation/features/writable/HdfsWritableTextTest.java
@@ -466,7 +466,7 @@ public class HdfsWritableTextTest extends
BaseWritableFeature {
FileFormatsUtils.prepareData(new WritableDataPreparer(), 1000, data);
// multiple it to file
String multiBlockedLocalFilePath = dataTempFolder +
"/multiBlockedData";
- FileFormatsUtils.prepareDataFile(data, 15000,
multiBlockedLocalFilePath);
+ FileFormatsUtils.prepareDataFile(data, 1000,
multiBlockedLocalFilePath);
String hdfsPath = hdfsWritePath +
"/copy_from_file_multi_block_no_compression";
writableExTable =
prepareWritableTable("pxf_text_multi_block_no_compression_w", hdfsPath, null);
@@ -480,7 +480,7 @@ public class HdfsWritableTextTest extends
BaseWritableFeature {
readableExTable =
prepareReadableTable("pxf_text_multi_block_no_compression_r", hdfsPath);
gpdb.runAnalyticQuery("SELECT COUNT(*) FROM " +
readableExTable.getName(),
- String.valueOf(1000 * 15000));
+ String.valueOf(1000 * 1000));
}
/**
@@ -495,7 +495,7 @@ public class HdfsWritableTextTest extends
BaseWritableFeature {
FileFormatsUtils.prepareData(new WritableDataPreparer(), 1000, data);
// multiple it to file
String multiBlockedLocalFilePath = (dataTempFolder +
"/multiBlockedData_gzip");
- FileFormatsUtils.prepareDataFile(data, 15000,
multiBlockedLocalFilePath);
+ FileFormatsUtils.prepareDataFile(data, 1000,
multiBlockedLocalFilePath);
String hdfsPath = hdfsWritePath + "/copy_from_file_multi_block_gzip";
writableExTable =
prepareWritableGzipTable("pxf_text_multi_block_gzip_w", hdfsPath);
@@ -509,7 +509,7 @@ public class HdfsWritableTextTest extends
BaseWritableFeature {
readableExTable = prepareReadableTable("pxf_text_multi_block_gzip_r",
hdfsPath);
gpdb.runAnalyticQuery("SELECT COUNT(*) FROM " +
readableExTable.getName(),
- String.valueOf(1000 * 15000));
+ String.valueOf(1000 * 1000));
}
/**
@@ -525,7 +525,7 @@ public class HdfsWritableTextTest extends
BaseWritableFeature {
FileFormatsUtils.prepareData(new WritableDataPreparer(), 1000, data);
// multiple it to file
String multiBlockedLocalFilePath = dataTempFolder +
"/multiBlockedData_bzip";
- FileFormatsUtils.prepareDataFile(data, 15000,
multiBlockedLocalFilePath);
+ FileFormatsUtils.prepareDataFile(data, 1000,
multiBlockedLocalFilePath);
String hdfsPath = hdfsWritePath + "/copy_from_file_multi_block_bzip2";
writableExTable =
prepareWritableBZip2Table("pxf_text_multi_block_bzip2_w", hdfsPath);
@@ -539,7 +539,7 @@ public class HdfsWritableTextTest extends
BaseWritableFeature {
readableExTable = prepareReadableTable("pxf_text_multi_block_bzip2_r",
hdfsPath);
gpdb.runAnalyticQuery("SELECT COUNT(*) FROM " +
readableExTable.getName(),
- String.valueOf(1000 * 15000));
+ String.valueOf(1000 * 1000));
}
/**
diff --git a/ci/docker/pxf-cbdb-dev/common/script/build_cloudberrry.sh
b/ci/docker/pxf-cbdb-dev/common/script/build_cloudberrry.sh
index 85404833..0f7858c5 100755
--- a/ci/docker/pxf-cbdb-dev/common/script/build_cloudberrry.sh
+++ b/ci/docker/pxf-cbdb-dev/common/script/build_cloudberrry.sh
@@ -20,11 +20,18 @@
# --------------------------------------------------------------------
# Build Cloudberry from source — works on both Ubuntu and Rocky/RHEL
+# Pull in shared helpers (log/die/retry). Sourced with an absolute path so
+# this script works whether invoked directly or via docker exec.
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+# shellcheck disable=SC1091
+source "${SCRIPT_DIR}/utils.sh"
+
# Install sudo & git
if command -v apt-get >/dev/null 2>&1; then
- sudo apt update && sudo apt install -y sudo git
+ retry sudo apt update
+ retry sudo apt install -y sudo git
elif command -v dnf >/dev/null 2>&1; then
- sudo dnf install -y --nobest sudo git
+ retry sudo dnf install -y --nobest sudo git
fi
# Required configuration
@@ -65,8 +72,8 @@ ulimit -a
# Install basic system packages
if command -v apt-get >/dev/null 2>&1; then
- sudo apt update
- sudo apt install -y bison \
+ retry sudo apt update
+ retry sudo apt install -y bison \
bzip2 \
cmake \
curl \
@@ -104,7 +111,7 @@ if command -v apt-get >/dev/null 2>&1; then
rsync \
libsnappy-dev
elif command -v dnf >/dev/null 2>&1; then
- sudo dnf install -y --nobest \
+ retry sudo dnf install -y --nobest \
bison \
bzip2 \
cmake \
diff --git a/ci/docker/pxf-cbdb-dev/common/script/build_pxf.sh
b/ci/docker/pxf-cbdb-dev/common/script/build_pxf.sh
index 6c4c1c83..bb8b3ae6 100755
--- a/ci/docker/pxf-cbdb-dev/common/script/build_pxf.sh
+++ b/ci/docker/pxf-cbdb-dev/common/script/build_pxf.sh
@@ -20,6 +20,12 @@
# --------------------------------------------------------------------
# Build and install PXF — works on both Ubuntu and Rocky/RHEL
+# Pull in shared helpers (log/die/retry). Sourced with an absolute path so
+# this script works whether invoked directly or via docker exec.
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+# shellcheck disable=SC1091
+source "${SCRIPT_DIR}/utils.sh"
+
# Auto-detect Java 11 path
if [ -d /usr/lib/jvm/java-11-openjdk-amd64 ]; then
JAVA_HOME=${JAVA_HOME:-/usr/lib/jvm/java-11-openjdk-amd64}
@@ -35,10 +41,10 @@ export PATH=$GPHOME/bin:$PATH
# Install Java 11 JDK and Maven
if command -v apt-get >/dev/null 2>&1; then
- sudo apt update
- sudo apt install -y openjdk-11-jdk maven
+ retry sudo apt update
+ retry sudo apt install -y openjdk-11-jdk maven
elif command -v dnf >/dev/null 2>&1; then
- sudo dnf install -y --nobest java-11-openjdk-devel maven
+ retry sudo dnf install -y --nobest java-11-openjdk-devel maven
fi
cd /home/gpadmin/workspace/cloudberry-pxf
diff --git a/ci/docker/pxf-cbdb-dev/common/script/entrypoint.sh
b/ci/docker/pxf-cbdb-dev/common/script/entrypoint.sh
index 7a4fe638..b6b2bdb1 100755
--- a/ci/docker/pxf-cbdb-dev/common/script/entrypoint.sh
+++ b/ci/docker/pxf-cbdb-dev/common/script/entrypoint.sh
@@ -58,13 +58,13 @@ detect_java_paths() {
setup_locale_and_packages() {
log "install base packages and locales"
if [ "$OS_FAMILY" = "deb" ]; then
- sudo apt-get update
- sudo apt-get install -y wget lsb-release locales maven unzip
openssh-server iproute2 sudo \
+ retry sudo apt-get update
+ retry sudo apt-get install -y wget lsb-release locales maven unzip
openssh-server iproute2 sudo \
openjdk-11-jre-headless openjdk-8-jre-headless
sudo locale-gen en_US.UTF-8 ru_RU.CP1251 ru_RU.UTF-8
sudo update-locale LANG=en_US.UTF-8
else
- sudo dnf install -y --nobest wget maven unzip openssh-server iproute sudo \
+ retry sudo dnf install -y --nobest wget maven unzip openssh-server iproute
sudo \
java-11-openjdk-headless java-1.8.0-openjdk-headless \
glibc-langpack-en glibc-locale-source
sudo localedef -c -i en_US -f UTF-8 en_US.UTF-8 || true
@@ -145,17 +145,17 @@ EOF
install_build_deps() {
if [ "$OS_FAMILY" = "deb" ]; then
- sudo apt update && sudo apt install -y sudo git
- sudo apt update
- sudo apt install -y bison bzip2 cmake curl flex gcc g++ iproute2
iputils-ping \
+ retry sudo apt update
+ retry sudo apt install -y sudo git
+ retry sudo apt install -y bison bzip2 cmake curl flex gcc g++ iproute2
iputils-ping \
language-pack-en locales libapr1-dev libbz2-dev libcurl4-gnutls-dev
libevent-dev \
libkrb5-dev libipc-run-perl libldap2-dev libpam0g-dev libprotobuf-dev
libreadline-dev \
libssl-dev libuv1-dev liblz4-dev libxerces-c-dev libxml2-dev libyaml-dev
libzstd-dev \
libperl-dev make pkg-config protobuf-compiler python3-dev python3-pip
python3-setuptools \
rsync libsnappy-dev
else
- sudo dnf install -y --nobest sudo git
- sudo dnf install -y --nobest --allowerasing bison bzip2 cmake curl flex
gcc gcc-c++ iproute iputils \
+ retry sudo dnf install -y --nobest sudo git
+ retry sudo dnf install -y --nobest --allowerasing bison bzip2 cmake curl
flex gcc gcc-c++ iproute iputils \
glibc-langpack-en glibc-locale-source apr-devel bzip2-devel
libcurl-devel libevent-devel \
krb5-devel perl-IPC-Run openldap-devel pam-devel protobuf-devel
readline-devel \
openssl-devel libuv-devel lz4-devel libxml2-devel libyaml-devel \
@@ -341,8 +341,13 @@ wait_for_datanode() {
local max_attempts=2
for _attempt in $(seq 1 ${max_attempts}); do
local dn_ready=false
- # Wait up to 90s (45 tries * 2s) for DataNode to register
- for _dn_try in $(seq 1 45); do
+ # Wait up to 180s (90 tries * 2s) for DataNode to register. GHA free-tier
+ # runners under I/O contention can take 90-180s for JVM cold-start +
+ # overlay2 block scan + NameNode handshake; the earlier 90s window was
+ # tight enough that Test PXF Rocky9 - smoke intermittently hit both
+ # attempts before DataNode came Live. Healthy runs still complete in
+ # 20-40s, so this only extends the tail — no cost on the happy path.
+ for _dn_try in $(seq 1 90); do
if hdfs dfsadmin -report 2>/dev/null | grep -q "Live datanodes.*[1-9]";
then
dn_ready=true
break
@@ -356,7 +361,7 @@ wait_for_datanode() {
fi
# DataNode didn't come up; diagnose and attempt restart
- log "DataNode not available after 90s (attempt
${_attempt}/${max_attempts})"
+ log "DataNode not available after 180s (attempt
${_attempt}/${max_attempts})"
log "--- DataNode diagnostic info ---"
# Check if DataNode process is alive
if command -v jps >/dev/null 2>&1; then
diff --git a/ci/docker/pxf-cbdb-dev/common/script/utils.sh
b/ci/docker/pxf-cbdb-dev/common/script/utils.sh
index b6936ef5..e6bdba9f 100755
--- a/ci/docker/pxf-cbdb-dev/common/script/utils.sh
+++ b/ci/docker/pxf-cbdb-dev/common/script/utils.sh
@@ -25,6 +25,27 @@ set -euo pipefail
log() { echo "[utils][$(date '+%F %T')] $*"; }
die() { log "ERROR $*"; exit 1; }
+# retry <cmd...> — run <cmd> up to $RETRY_MAX_ATTEMPTS times (default 3),
+# waiting $RETRY_DELAY seconds between attempts (default 15). Used to
+# harden CI against transient upstream failures: dnf/apt mirror hiccups,
+# Maven Central connect flakes, image registry throttling, etc. Exits
+# with the last command's exit code on final failure.
+retry() {
+ local -r max_attempts=${RETRY_MAX_ATTEMPTS:-3}
+ local -r delay=${RETRY_DELAY:-15}
+ local attempt=1
+ until "$@"; do
+ if [ "$attempt" -ge "$max_attempts" ]; then
+ log "retry: '$*' failed after $attempt attempts, giving up"
+ return 1
+ fi
+ log "retry: '$*' failed (attempt $attempt/$max_attempts), waiting
${delay}s"
+ sleep "$delay"
+ attempt=$((attempt + 1))
+ done
+ return 0
+}
+
wait_port() {
local host="$1" port="$2" retries="${3:-10}" sleep_sec="${4:-2}"
local i
diff --git a/ci/docker/pxf-cbdb-dev/rocky9/docker-compose.yml
b/ci/docker/pxf-cbdb-dev/rocky9/docker-compose.yml
index 37738078..93e818e1 100644
--- a/ci/docker/pxf-cbdb-dev/rocky9/docker-compose.yml
+++ b/ci/docker/pxf-cbdb-dev/rocky9/docker-compose.yml
@@ -34,11 +34,23 @@ services:
hostname: mdw
depends_on:
- singlecluster
+ environment:
+ # Pin container TZ so JVM's ZoneId.systemDefault() (used by
+ # ParquetTypeConverter for INT96 timestamp encode/decode) is the
+ # same across distros. Matches the PGOPTIONS timezone='GMT-1' set
+ # by run_tests.sh, keeping the Parquet-vs-PG timestamp path
+ # internally consistent.
+ TZ: Etc/GMT-1
ports:
- "2222:22"
volumes:
- ../../../../../cloudberry-pxf:/home/gpadmin/workspace/cloudberry-pxf
- ../../../../../cloudberry:/home/gpadmin/workspace/cloudberry
+ # Share host's Maven local repo with the container so mvn dependency
+ # downloads survive across runs via actions/cache. Neutralises transient
+ # 5xx from Maven Central and single-source repos (top-q.co.il for
+ # JSystem) once the cache is warm.
+ - ../../../../../.m2:/home/gpadmin/.m2
command: ["tail", "-f", "/dev/null"]
networks:
diff --git a/ci/docker/pxf-cbdb-dev/ubuntu/docker-compose.yml
b/ci/docker/pxf-cbdb-dev/ubuntu/docker-compose.yml
index 02519cb9..eee4cee2 100644
--- a/ci/docker/pxf-cbdb-dev/ubuntu/docker-compose.yml
+++ b/ci/docker/pxf-cbdb-dev/ubuntu/docker-compose.yml
@@ -33,11 +33,23 @@ services:
hostname: mdw
depends_on:
- singlecluster
+ environment:
+ # Pin container TZ so JVM's ZoneId.systemDefault() (used by
+ # ParquetTypeConverter for INT96 timestamp encode/decode) is the
+ # same across distros. Matches the PGOPTIONS timezone='GMT-1' set
+ # by run_tests.sh, keeping the Parquet-vs-PG timestamp path
+ # internally consistent.
+ TZ: Etc/GMT-1
ports:
- "2222:22"
volumes:
- ../../../../../cloudberry-pxf:/home/gpadmin/workspace/cloudberry-pxf
- ../../../../../cloudberry:/home/gpadmin/workspace/cloudberry
+ # Share host's Maven local repo with the container so mvn dependency
+ # downloads survive across runs via actions/cache. Neutralises transient
+ # 5xx from Maven Central and single-source repos (top-q.co.il for
+ # JSystem) once the cache is warm.
+ - ../../../../../.m2:/home/gpadmin/.m2
command: ["tail", "-f", "/dev/null"]
networks:
diff --git a/ci/singlecluster/templates/hadoop/etc/hadoop/hdfs-site.xml
b/ci/singlecluster/templates/hadoop/etc/hadoop/hdfs-site.xml
index e75a7eba..d870911c 100755
--- a/ci/singlecluster/templates/hadoop/etc/hadoop/hdfs-site.xml
+++ b/ci/singlecluster/templates/hadoop/etc/hadoop/hdfs-site.xml
@@ -34,11 +34,46 @@
<value>3</value>
</property>
<property>
- <name>dfs.datanode.socket.write.timeout</name>
+ <name>dfs.datanode.socket.write.timeout</name>
<value>0</value>
<description>
used for sockets to and from datanodes. It is 8 minutes by
default. Some users set this to 0, effectively disabling the write timeout.
- </description>
+ </description>
+ </property>
+ <property>
+ <name>dfs.client.socket-timeout</name>
+ <value>180000</value>
+ <description>
+ HDFS client-side socket timeout in ms (default 60s). Raised to
+ 3 minutes so shared-runner CI (GitHub Actions free tier) does
+ not spuriously abort large-file writes when the DataNode is
+ slow to ACK due to noisy-neighbor I/O contention. 3 minutes
+ is ~3x the worst observed ACK stall on GHA free runners while
+ still failing fast when a DataNode is genuinely dead. Symptom
+ without this: HdfsWritableTextTest multi-block variants
+ silently drop their write and the readback finds no data.
+ </description>
+ </property>
+ <property>
+ <name>dfs.blocksize</name>
+ <value>16777216</value>
+ <description>
+ Default HDFS block size in bytes (16 MB, down from the Hadoop
+ default of 128 MB). This is a test cluster: smaller blocks
+ let "multi-block" test coverage kick in on much smaller
+ input data (e.g. HdfsWritableTextTest's
+ copyFromFileMultiBlockedData* variants), keeping the tests'
+ original intent (cross-block-boundary reader/writer paths)
+ while cutting write I/O by an order of magnitude — critical
+ on shared GHA runners that otherwise time out.
+ 16 MB (not 4 MB) leaves headroom for existing row sizes such
+ as textFormatWideRowsInsert's 10 MiB rows — they fit inside
+ one block, so cross-block row-boundary paths are still
+ exercised by copyFromFileMultiBlockedData* (60 MB / 16 MB
+ ≈ 4 blocks) rather than by every row of every wide-row test.
+ Real-world deployments still use the Hadoop default; this is
+ CI-only.
+ </description>
</property>
<property>
<name>dfs.webhdfs.enabled</name>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]