diff --git a/.blazar.yaml b/.blazar.yaml
new file mode 100644
index 000000000000..4335a8f33d93
--- /dev/null
+++ b/.blazar.yaml
@@ -0,0 +1,25 @@
+buildpack:
+ name: Blazar-Buildpack-Java-oss-fork
+
+env:
+ MAVEN_PHASE: "package assembly:single deploy"
+ HADOOP_DEP_VERSION: "3.3.6-hubspot-SNAPSHOT"
+ MAVEN_BUILD_ARGS: "-Phadoop-3.0 -Dhadoop.profile=3.0 -Dhadoop-three.version=$HADOOP_DEP_VERSION -Dgpg.skip=true -DskipTests -DdeployAtEnd -pl hbase-assembly -am -T1C"
+
+ # Below variables are generated in prepare_environment.sh.
+ # The build environment requires environment variables to be explicitly defined before they may
+ # be modified by the `write-build-env-var` utilty script to persist changes to an environment variable
+ # throughout a build
+ REPO_NAME: ""
+ SET_VERSION: ""
+ HBASE_VERSION: ""
+ PKG_RELEASE: ""
+ FULL_BUILD_VERSION: ""
+
+before:
+ - description: "Prepare build environment"
+ commands:
+ - $WORKSPACE/build-scripts/prepare_environment.sh
+
+provides:
+ - hbase
diff --git a/.build-jdk17 b/.build-jdk17
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/.github/workflows/yetus-general-check.yml b/.github/workflows/yetus-general-check.yml
new file mode 100644
index 000000000000..40e9589d4020
--- /dev/null
+++ b/.github/workflows/yetus-general-check.yml
@@ -0,0 +1,141 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# yamllint disable rule:line-length
+---
+name: Yetus General Check
+
+"on":
+ pull_request:
+ types: [opened, synchronize, reopened]
+
+permissions: {}
+
+jobs:
+ general-check:
+ runs-on: ubuntu-latest
+ timeout-minutes: 600
+ permissions:
+ contents: read
+ statuses: write
+
+ env:
+ YETUS_VERSION: '0.15.0'
+
+ steps:
+ - name: Checkout HBase
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ path: src
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: Set up JDK 11
+ uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+
+ - name: Maven cache
+ uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
+ with:
+ path: ~/.m2
+ key: hbase-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ hbase-m2-
+
+ - name: Download Yetus
+ run: |
+ mkdir -p yetus
+ cd yetus
+ bash "${{ github.workspace }}/src/dev-support/jenkins-scripts/cache-apache-project-artifact.sh" \
+ --keys 'https://downloads.apache.org/yetus/KEYS' \
+ --verify-tar-gz \
+ ./apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz \
+ yetus/${{ env.YETUS_VERSION }}/apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+ tar --strip-components=1 -xzf apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+ rm apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+
+ - name: Run Yetus General Check
+ env:
+ ARCHIVE_PATTERN_LIST: "TEST-*.xml,org.apache.h*.txt,*.dumpstream,*.dump"
+ CHANGE_TARGET: "${{ github.base_ref }}"
+ DOCKERFILE: "${{ github.workspace }}/src/dev-support/docker/Dockerfile"
+ GITHUB_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_USER: ${{ github.actor }}
+ HADOOP_PROFILE: "3.0"
+ JAVA8_HOME: "/usr/lib/jvm/java-8"
+ PATCHDIR: "${{ github.workspace }}/yetus-general-check/output"
+ PLUGINS: "all,-javadoc,-jira,-shadedjars,-unit"
+ SET_JAVA_HOME: "/usr/lib/jvm/java-11"
+ SOURCEDIR: "${{ github.workspace }}/src"
+ TESTS_FILTER: "checkstyle,javac,pylint,shellcheck,shelldocs,blanks,perlcritic,ruby-lint,rubocop"
+ YETUSDIR: "${{ github.workspace }}/yetus"
+ AUTHOR_IGNORE_LIST: "src/main/asciidoc/_chapters/developer.adoc"
+ BLANKS_EOL_IGNORE_FILE: "dev-support/blanks-eol-ignore.txt"
+ BLANKS_TABS_IGNORE_FILE: "dev-support/blanks-tabs-ignore.txt"
+ EXCLUDE_TESTS_URL: "https://ci-hbase.apache.org/job/HBase-Find-Flaky-Tests/job/${{ github.base_ref }}/lastSuccessfulBuild/artifact/output/excludes"
+ BUILD_THREAD: "4"
+ SUREFIRE_FIRST_PART_FORK_COUNT: "1.0C"
+ SUREFIRE_SECOND_PART_FORK_COUNT: "0.5C"
+ BRANCH_NAME: "${{ github.base_ref }}"
+ DEBUG: 'true'
+ run: |
+ cd "${{ github.workspace }}"
+ bash src/dev-support/jenkins_precommit_github_yetus.sh
+
+ - name: Publish Job Summary
+ if: always()
+ run: |
+ cd "${{ github.workspace }}"
+ python3 src/dev-support/yetus_console_to_md.py yetus-general-check/output >> $GITHUB_STEP_SUMMARY
+
+ - name: Publish Test Results
+ if: always()
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ with:
+ name: yetus-general-check-output
+ path: ${{ github.workspace }}/yetus-general-check/output
+ retention-days: 7
+
+ zizmor:
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ permissions:
+ contents: read
+
+ steps:
+ - name: Check for workflow changes
+ id: changes
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ if gh pr diff "${{ github.event.pull_request.number }}" --repo "${{ github.repository }}" --name-only | grep -q '^\.github/workflows/'; then
+ echo "changed=true" >> "$GITHUB_OUTPUT"
+ else
+ echo "changed=false" >> "$GITHUB_OUTPUT"
+ fi
+
+ - name: Checkout HBase
+ if: steps.changes.outputs.changed == 'true'
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+
+ - name: Run zizmor
+ if: steps.changes.outputs.changed == 'true'
+ run: pipx run zizmor --min-severity=medium .github/workflows/
diff --git a/.github/workflows/yetus-jdk11-hadoop3-compile-check.yml b/.github/workflows/yetus-jdk11-hadoop3-compile-check.yml
new file mode 100644
index 000000000000..603066ff5e5d
--- /dev/null
+++ b/.github/workflows/yetus-jdk11-hadoop3-compile-check.yml
@@ -0,0 +1,111 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# yamllint disable rule:line-length
+---
+name: Yetus JDK11 Hadoop3 Compile Check
+
+"on":
+ pull_request:
+ types: [opened, synchronize, reopened]
+
+permissions: {}
+
+jobs:
+ jdk11-hadoop3-compile-check:
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+ permissions:
+ contents: read
+ statuses: write
+
+ env:
+ YETUS_VERSION: '0.15.0'
+
+ steps:
+ - name: Checkout HBase
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ path: src
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: Set up JDK 11
+ uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+
+ - name: Maven cache
+ uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
+ with:
+ path: ~/.m2
+ key: hbase-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ hbase-m2-
+
+ - name: Download Yetus
+ run: |
+ mkdir -p yetus
+ cd yetus
+ bash "${{ github.workspace }}/src/dev-support/jenkins-scripts/cache-apache-project-artifact.sh" \
+ --keys 'https://downloads.apache.org/yetus/KEYS' \
+ --verify-tar-gz \
+ ./apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz \
+ yetus/${{ env.YETUS_VERSION }}/apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+ tar --strip-components=1 -xzf apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+ rm apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+
+ - name: Run Yetus JDK11 Hadoop3 Compile Check
+ env:
+ ARCHIVE_PATTERN_LIST: "TEST-*.xml,org.apache.h*.txt,*.dumpstream,*.dump"
+ DOCKERFILE: "${{ github.workspace }}/src/dev-support/docker/Dockerfile"
+ GITHUB_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_USER: ${{ github.actor }}
+ HADOOP_PROFILE: "3.0"
+ JAVA8_HOME: "/usr/lib/jvm/java-8"
+ PATCHDIR: "${{ github.workspace }}/yetus-jdk11-hadoop3-compile-check/output"
+ PLUGINS: "compile,github,htmlout,javac,javadoc,maven,mvninstall,shadedjars"
+ SET_JAVA_HOME: "/usr/lib/jvm/java-11"
+ SOURCEDIR: "${{ github.workspace }}/src"
+ TESTS_FILTER: "javac,javadoc"
+ YETUSDIR: "${{ github.workspace }}/yetus"
+ AUTHOR_IGNORE_LIST: "src/main/asciidoc/_chapters/developer.adoc"
+ BLANKS_EOL_IGNORE_FILE: "dev-support/blanks-eol-ignore.txt"
+ BLANKS_TABS_IGNORE_FILE: "dev-support/blanks-tabs-ignore.txt"
+ BUILD_THREAD: "4"
+ BRANCH_NAME: "${{ github.base_ref }}"
+ CHANGE_TARGET: "${{ github.base_ref }}"
+ SKIP_ERRORPRONE: 'true'
+ DEBUG: 'true'
+ run: |
+ cd "${{ github.workspace }}"
+ bash src/dev-support/jenkins_precommit_github_yetus.sh
+
+ - name: Publish Job Summary
+ if: always()
+ run: |
+ cd "${{ github.workspace }}"
+ python3 src/dev-support/yetus_console_to_md.py yetus-jdk11-hadoop3-compile-check/output >> $GITHUB_STEP_SUMMARY
+
+ - name: Publish Results
+ if: always()
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ with:
+ name: yetus-jdk11-hadoop3-compile-check-output
+ path: ${{ github.workspace }}/yetus-jdk11-hadoop3-compile-check/output
+ retention-days: 7
diff --git a/.github/workflows/yetus-jdk11-hadoop3-unit-check.yml b/.github/workflows/yetus-jdk11-hadoop3-unit-check.yml
new file mode 100644
index 000000000000..627f610c95f5
--- /dev/null
+++ b/.github/workflows/yetus-jdk11-hadoop3-unit-check.yml
@@ -0,0 +1,133 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# yamllint disable rule:line-length
+---
+name: Yetus JDK11 Hadoop3 Unit Check
+
+"on":
+ pull_request:
+ types: [opened, synchronize, reopened]
+
+permissions: {}
+
+jobs:
+ jdk11-hadoop3-unit-check:
+ runs-on: ubuntu-latest
+ timeout-minutes: 360
+ permissions:
+ contents: read
+ statuses: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - name: "small"
+ test_profile: "runSmallTests"
+ - name: "medium"
+ test_profile: "runMediumTests"
+ # Large tests split alphabetically by class name (after "Test" prefix)
+ # Wave 1: Test[A-H]*, Wave 2: Test[I-R]*, Wave 3: Test[S-Z]*
+ - name: "large-wave-1"
+ test_profile: "runLargeTests-wave1"
+ - name: "large-wave-2"
+ test_profile: "runLargeTests-wave2"
+ - name: "large-wave-3"
+ test_profile: "runLargeTests-wave3"
+
+ name: ${{ matrix.name }}
+
+ env:
+ YETUS_VERSION: '0.15.0'
+
+ steps:
+ - name: Checkout HBase
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ path: src
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: Set up JDK 11
+ uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+
+ - name: Maven cache
+ uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
+ with:
+ path: ~/.m2
+ key: hbase-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ hbase-m2-
+
+ - name: Download Yetus
+ run: |
+ mkdir -p yetus
+ cd yetus
+ bash "${{ github.workspace }}/src/dev-support/jenkins-scripts/cache-apache-project-artifact.sh" \
+ --keys 'https://downloads.apache.org/yetus/KEYS' \
+ --verify-tar-gz \
+ ./apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz \
+ yetus/${{ env.YETUS_VERSION }}/apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+ tar --strip-components=1 -xzf apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+ rm apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+
+ - name: Run Yetus JDK11 Hadoop3 Unit Check
+ env:
+ ARCHIVE_PATTERN_LIST: "TEST-*.xml,org.apache.h*.txt,*.dumpstream,*.dump"
+ DOCKERFILE: "${{ github.workspace }}/src/dev-support/docker/Dockerfile"
+ GITHUB_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_USER: ${{ github.actor }}
+ HADOOP_PROFILE: "3.0"
+ JAVA8_HOME: "/usr/lib/jvm/java-8"
+ PATCHDIR: "${{ github.workspace }}/yetus-jdk11-hadoop3-unit-check/output"
+ PLUGINS: "github,htmlout,maven,unit"
+ SET_JAVA_HOME: "/usr/lib/jvm/java-11"
+ SOURCEDIR: "${{ github.workspace }}/src"
+ YETUSDIR: "${{ github.workspace }}/yetus"
+ AUTHOR_IGNORE_LIST: "src/main/asciidoc/_chapters/developer.adoc"
+ BLANKS_EOL_IGNORE_FILE: "dev-support/blanks-eol-ignore.txt"
+ BLANKS_TABS_IGNORE_FILE: "dev-support/blanks-tabs-ignore.txt"
+ EXCLUDE_TESTS_URL: "https://ci-hbase.apache.org/job/HBase-Find-Flaky-Tests/job/${{ github.base_ref }}/lastSuccessfulBuild/artifact/output/excludes"
+ BUILD_THREAD: "4"
+ SUREFIRE_FIRST_PART_FORK_COUNT: "1.0C"
+ SUREFIRE_SECOND_PART_FORK_COUNT: "0.5C"
+ BRANCH_NAME: "${{ github.base_ref }}"
+ CHANGE_TARGET: "${{ github.base_ref }}"
+ SKIP_ERRORPRONE: 'true'
+ DEBUG: 'true'
+ TEST_PROFILE: ${{ matrix.test_profile }}
+ run: |
+ cd "${{ github.workspace }}"
+ bash src/dev-support/jenkins_precommit_github_yetus.sh
+
+ - name: Publish Job Summary
+ if: always()
+ run: |
+ cd "${{ github.workspace }}"
+ python3 src/dev-support/yetus_console_to_md.py yetus-jdk11-hadoop3-unit-check/output >> $GITHUB_STEP_SUMMARY
+
+ - name: Publish Test Results
+ if: always()
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ with:
+ name: yetus-jdk11-hadoop3-unit-check-${{ matrix.name }}
+ path: ${{ github.workspace }}/yetus-jdk11-hadoop3-unit-check/output
+ retention-days: 7
diff --git a/.github/workflows/yetus-jdk17-hadoop3-compile-check.yml b/.github/workflows/yetus-jdk17-hadoop3-compile-check.yml
new file mode 100644
index 000000000000..17abf8990d9c
--- /dev/null
+++ b/.github/workflows/yetus-jdk17-hadoop3-compile-check.yml
@@ -0,0 +1,110 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# yamllint disable rule:line-length
+---
+name: Yetus JDK17 Hadoop3 Compile Check
+
+"on":
+ pull_request:
+ types: [opened, synchronize, reopened]
+
+permissions:
+ contents: read
+ statuses: write
+
+jobs:
+ jdk17-hadoop3-compile-check:
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+
+ env:
+ YETUS_VERSION: '0.15.0'
+
+ steps:
+ - name: Checkout HBase
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ path: src
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+
+ - name: Maven cache
+ uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
+ with:
+ path: ~/.m2
+ key: hbase-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ hbase-m2-
+
+ - name: Download Yetus
+ run: |
+ mkdir -p yetus
+ cd yetus
+ bash "${{ github.workspace }}/src/dev-support/jenkins-scripts/cache-apache-project-artifact.sh" \
+ --keys 'https://downloads.apache.org/yetus/KEYS' \
+ --verify-tar-gz \
+ ./apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz \
+ yetus/${{ env.YETUS_VERSION }}/apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+ tar --strip-components=1 -xzf apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+ rm apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+
+ - name: Run Yetus JDK17 Hadoop3 Compile Check
+ env:
+ ARCHIVE_PATTERN_LIST: "TEST-*.xml,org.apache.h*.txt,*.dumpstream,*.dump"
+ DOCKERFILE: "${{ github.workspace }}/src/dev-support/docker/Dockerfile"
+ GITHUB_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_USER: ${{ github.actor }}
+ HADOOP_PROFILE: "3.0"
+ JAVA8_HOME: "/usr/lib/jvm/java-8"
+ PATCHDIR: "${{ github.workspace }}/yetus-jdk17-hadoop3-compile-check/output"
+ PLUGINS: "compile,github,htmlout,javac,javadoc,maven,mvninstall,shadedjars"
+ SET_JAVA_HOME: "/usr/lib/jvm/java-17"
+ SOURCEDIR: "${{ github.workspace }}/src"
+ TESTS_FILTER: "javac,javadoc"
+ YETUSDIR: "${{ github.workspace }}/yetus"
+ AUTHOR_IGNORE_LIST: "src/main/asciidoc/_chapters/developer.adoc"
+ BLANKS_EOL_IGNORE_FILE: "dev-support/blanks-eol-ignore.txt"
+ BLANKS_TABS_IGNORE_FILE: "dev-support/blanks-tabs-ignore.txt"
+ BUILD_THREAD: "4"
+ BRANCH_NAME: "${{ github.base_ref }}"
+ CHANGE_TARGET: "${{ github.base_ref }}"
+ SKIP_ERRORPRONE: 'true'
+ DEBUG: 'true'
+ run: |
+ cd "${{ github.workspace }}"
+ bash src/dev-support/jenkins_precommit_github_yetus.sh
+
+ - name: Publish Job Summary
+ if: always()
+ run: |
+ cd "${{ github.workspace }}"
+ python3 src/dev-support/yetus_console_to_md.py yetus-jdk17-hadoop3-compile-check/output >> $GITHUB_STEP_SUMMARY
+
+ - name: Publish Results
+ if: always()
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ with:
+ name: yetus-jdk17-hadoop3-compile-check-output
+ path: ${{ github.workspace }}/yetus-jdk17-hadoop3-compile-check/output
+ retention-days: 7
diff --git a/.github/workflows/yetus-jdk17-hadoop3-unit-check.yml b/.github/workflows/yetus-jdk17-hadoop3-unit-check.yml
new file mode 100644
index 000000000000..571b6155dc37
--- /dev/null
+++ b/.github/workflows/yetus-jdk17-hadoop3-unit-check.yml
@@ -0,0 +1,132 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# yamllint disable rule:line-length
+---
+name: Yetus JDK17 Hadoop3 Unit Check
+
+"on":
+ pull_request:
+ types: [opened, synchronize, reopened]
+
+permissions:
+ contents: read
+ statuses: write
+
+jobs:
+ jdk17-hadoop3-unit-check:
+ runs-on: ubuntu-latest
+ timeout-minutes: 360
+
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - name: "small"
+ test_profile: "runSmallTests"
+ - name: "medium"
+ test_profile: "runMediumTests"
+ # Large tests split alphabetically by class name (after "Test" prefix)
+ # Wave 1: Test[A-H]*, Wave 2: Test[I-R]*, Wave 3: Test[S-Z]*
+ - name: "large-wave-1"
+ test_profile: "runLargeTests-wave1"
+ - name: "large-wave-2"
+ test_profile: "runLargeTests-wave2"
+ - name: "large-wave-3"
+ test_profile: "runLargeTests-wave3"
+
+ name: ${{ matrix.name }}
+
+ env:
+ YETUS_VERSION: '0.15.0'
+
+ steps:
+ - name: Checkout HBase
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ path: src
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+
+ - name: Maven cache
+ uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
+ with:
+ path: ~/.m2
+ key: hbase-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ hbase-m2-
+
+ - name: Download Yetus
+ run: |
+ mkdir -p yetus
+ cd yetus
+ bash "${{ github.workspace }}/src/dev-support/jenkins-scripts/cache-apache-project-artifact.sh" \
+ --keys 'https://downloads.apache.org/yetus/KEYS' \
+ --verify-tar-gz \
+ ./apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz \
+ yetus/${{ env.YETUS_VERSION }}/apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+ tar --strip-components=1 -xzf apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+ rm apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+
+ - name: Run Yetus JDK17 Hadoop3 Unit Check
+ env:
+ ARCHIVE_PATTERN_LIST: "TEST-*.xml,org.apache.h*.txt,*.dumpstream,*.dump"
+ DOCKERFILE: "${{ github.workspace }}/src/dev-support/docker/Dockerfile"
+ GITHUB_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_USER: ${{ github.actor }}
+ HADOOP_PROFILE: "3.0"
+ JAVA8_HOME: "/usr/lib/jvm/java-8"
+ PATCHDIR: "${{ github.workspace }}/yetus-jdk17-hadoop3-unit-check/output"
+ PLUGINS: "github,htmlout,maven,unit"
+ SET_JAVA_HOME: "/usr/lib/jvm/java-17"
+ SOURCEDIR: "${{ github.workspace }}/src"
+ YETUSDIR: "${{ github.workspace }}/yetus"
+ AUTHOR_IGNORE_LIST: "src/main/asciidoc/_chapters/developer.adoc"
+ BLANKS_EOL_IGNORE_FILE: "dev-support/blanks-eol-ignore.txt"
+ BLANKS_TABS_IGNORE_FILE: "dev-support/blanks-tabs-ignore.txt"
+ EXCLUDE_TESTS_URL: "https://ci-hbase.apache.org/job/HBase-Find-Flaky-Tests/job/${{ github.base_ref }}/lastSuccessfulBuild/artifact/output/excludes"
+ BUILD_THREAD: "4"
+ SUREFIRE_FIRST_PART_FORK_COUNT: "1.0C"
+ SUREFIRE_SECOND_PART_FORK_COUNT: "0.5C"
+ BRANCH_NAME: "${{ github.base_ref }}"
+ CHANGE_TARGET: "${{ github.base_ref }}"
+ SKIP_ERRORPRONE: 'true'
+ DEBUG: 'true'
+ TEST_PROFILE: ${{ matrix.test_profile }}
+ run: |
+ cd "${{ github.workspace }}"
+ bash src/dev-support/jenkins_precommit_github_yetus.sh
+
+ - name: Publish Job Summary
+ if: always()
+ run: |
+ cd "${{ github.workspace }}"
+ python3 src/dev-support/yetus_console_to_md.py yetus-jdk17-hadoop3-unit-check/output >> $GITHUB_STEP_SUMMARY
+
+ - name: Publish Test Results
+ if: always()
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ with:
+ name: yetus-jdk17-hadoop3-unit-check-${{ matrix.name }}
+ path: ${{ github.workspace }}/yetus-jdk17-hadoop3-unit-check/output
+ retention-days: 7
diff --git a/.github/workflows/yetus-jdk8-hadoop2-compile-check.yml b/.github/workflows/yetus-jdk8-hadoop2-compile-check.yml
new file mode 100644
index 000000000000..26b27d850356
--- /dev/null
+++ b/.github/workflows/yetus-jdk8-hadoop2-compile-check.yml
@@ -0,0 +1,110 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# yamllint disable rule:line-length
+---
+name: Yetus JDK8 Hadoop2 Compile Check
+
+"on":
+ pull_request:
+ types: [opened, synchronize, reopened]
+
+permissions: {}
+
+jobs:
+ jdk8-hadoop2-compile-check:
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+ permissions:
+ contents: read
+ statuses: write
+
+ env:
+ YETUS_VERSION: '0.15.0'
+
+ steps:
+ - name: Checkout HBase
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ path: src
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: Set up JDK 8
+ uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
+ with:
+ java-version: '8'
+ distribution: 'temurin'
+
+ - name: Maven cache
+ uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
+ with:
+ path: ~/.m2
+ key: hbase-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ hbase-m2-
+
+ - name: Download Yetus
+ run: |
+ mkdir -p yetus
+ cd yetus
+ bash "${{ github.workspace }}/src/dev-support/jenkins-scripts/cache-apache-project-artifact.sh" \
+ --keys 'https://downloads.apache.org/yetus/KEYS' \
+ --verify-tar-gz \
+ ./apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz \
+ yetus/${{ env.YETUS_VERSION }}/apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+ tar --strip-components=1 -xzf apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+ rm apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+
+ - name: Run Yetus JDK8 Hadoop2 Compile Check
+ env:
+ ARCHIVE_PATTERN_LIST: "TEST-*.xml,org.apache.h*.txt,*.dumpstream,*.dump"
+ DOCKERFILE: "${{ github.workspace }}/src/dev-support/docker/Dockerfile"
+ GITHUB_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_USER: ${{ github.actor }}
+ JAVA8_HOME: "/usr/lib/jvm/java-8"
+ PATCHDIR: "${{ github.workspace }}/yetus-jdk8-hadoop2-compile-check/output"
+ PLUGINS: "compile,github,htmlout,javac,javadoc,maven,mvninstall,shadedjars"
+ SET_JAVA_HOME: "/usr/lib/jvm/java-8"
+ SOURCEDIR: "${{ github.workspace }}/src"
+ TESTS_FILTER: "javac,javadoc"
+ YETUSDIR: "${{ github.workspace }}/yetus"
+ AUTHOR_IGNORE_LIST: "src/main/asciidoc/_chapters/developer.adoc"
+ BLANKS_EOL_IGNORE_FILE: "dev-support/blanks-eol-ignore.txt"
+ BLANKS_TABS_IGNORE_FILE: "dev-support/blanks-tabs-ignore.txt"
+ BUILD_THREAD: "4"
+ BRANCH_NAME: "${{ github.base_ref }}"
+ CHANGE_TARGET: "${{ github.base_ref }}"
+ SKIP_ERRORPRONE: 'true'
+ DEBUG: 'true'
+ run: |
+ cd "${{ github.workspace }}"
+ bash src/dev-support/jenkins_precommit_github_yetus.sh
+
+ - name: Publish Job Summary
+ if: always()
+ run: |
+ cd "${{ github.workspace }}"
+ python3 src/dev-support/yetus_console_to_md.py yetus-jdk8-hadoop2-compile-check/output >> $GITHUB_STEP_SUMMARY
+
+ - name: Publish Results
+ if: always()
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ with:
+ name: yetus-jdk8-hadoop2-compile-check-output
+ path: ${{ github.workspace }}/yetus-jdk8-hadoop2-compile-check/output
+ retention-days: 7
diff --git a/.github/workflows/yetus-jdk8-hadoop2-unit-check.yml b/.github/workflows/yetus-jdk8-hadoop2-unit-check.yml
new file mode 100644
index 000000000000..60f040480db9
--- /dev/null
+++ b/.github/workflows/yetus-jdk8-hadoop2-unit-check.yml
@@ -0,0 +1,132 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# yamllint disable rule:line-length
+---
+name: Yetus JDK8 Hadoop2 Unit Check
+
+"on":
+ pull_request:
+ types: [opened, synchronize, reopened]
+
+permissions: {}
+
+jobs:
+ jdk8-hadoop2-unit-check:
+ runs-on: ubuntu-latest
+ timeout-minutes: 360
+ permissions:
+ contents: read
+ statuses: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - name: "small"
+ test_profile: "runSmallTests"
+ - name: "medium"
+ test_profile: "runMediumTests"
+ # Large tests split alphabetically by class name (after "Test" prefix)
+ # Wave 1: Test[A-H]*, Wave 2: Test[I-R]*, Wave 3: Test[S-Z]*
+ - name: "large-wave-1"
+ test_profile: "runLargeTests-wave1"
+ - name: "large-wave-2"
+ test_profile: "runLargeTests-wave2"
+ - name: "large-wave-3"
+ test_profile: "runLargeTests-wave3"
+
+ name: ${{ matrix.name }}
+
+ env:
+ YETUS_VERSION: '0.15.0'
+
+ steps:
+ - name: Checkout HBase
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ path: src
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: Set up JDK 8
+ uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
+ with:
+ java-version: '8'
+ distribution: 'temurin'
+
+ - name: Maven cache
+ uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
+ with:
+ path: ~/.m2
+ key: hbase-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ hbase-m2-
+
+ - name: Download Yetus
+ run: |
+ mkdir -p yetus
+ cd yetus
+ bash "${{ github.workspace }}/src/dev-support/jenkins-scripts/cache-apache-project-artifact.sh" \
+ --keys 'https://downloads.apache.org/yetus/KEYS' \
+ --verify-tar-gz \
+ ./apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz \
+ yetus/${{ env.YETUS_VERSION }}/apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+ tar --strip-components=1 -xzf apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+ rm apache-yetus-${{ env.YETUS_VERSION }}-bin.tar.gz
+
+ - name: Run Yetus JDK8 Hadoop2 Unit Check
+ env:
+ ARCHIVE_PATTERN_LIST: "TEST-*.xml,org.apache.h*.txt,*.dumpstream,*.dump"
+ DOCKERFILE: "${{ github.workspace }}/src/dev-support/docker/Dockerfile"
+ GITHUB_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_USER: ${{ github.actor }}
+ JAVA8_HOME: "/usr/lib/jvm/java-8"
+ PATCHDIR: "${{ github.workspace }}/yetus-jdk8-hadoop2-unit-check/output"
+ PLUGINS: "github,htmlout,maven,unit"
+ SET_JAVA_HOME: "/usr/lib/jvm/java-8"
+ SOURCEDIR: "${{ github.workspace }}/src"
+ YETUSDIR: "${{ github.workspace }}/yetus"
+ AUTHOR_IGNORE_LIST: "src/main/asciidoc/_chapters/developer.adoc"
+ BLANKS_EOL_IGNORE_FILE: "dev-support/blanks-eol-ignore.txt"
+ BLANKS_TABS_IGNORE_FILE: "dev-support/blanks-tabs-ignore.txt"
+ EXCLUDE_TESTS_URL: "https://ci-hbase.apache.org/job/HBase-Find-Flaky-Tests/job/${{ github.base_ref }}/lastSuccessfulBuild/artifact/output/excludes"
+ BUILD_THREAD: "4"
+ SUREFIRE_FIRST_PART_FORK_COUNT: "1.0C"
+ SUREFIRE_SECOND_PART_FORK_COUNT: "0.5C"
+ BRANCH_NAME: "${{ github.base_ref }}"
+ CHANGE_TARGET: "${{ github.base_ref }}"
+ SKIP_ERRORPRONE: 'true'
+ DEBUG: 'true'
+ TEST_PROFILE: ${{ matrix.test_profile }}
+ run: |
+ cd "${{ github.workspace }}"
+ bash src/dev-support/jenkins_precommit_github_yetus.sh
+
+ - name: Publish Job Summary
+ if: always()
+ run: |
+ cd "${{ github.workspace }}"
+ python3 src/dev-support/yetus_console_to_md.py yetus-jdk8-hadoop2-unit-check/output >> $GITHUB_STEP_SUMMARY
+
+ - name: Publish Test Results
+ if: always()
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ with:
+ name: yetus-jdk8-hadoop2-unit-check-${{ matrix.name }}
+ path: ${{ github.workspace }}/yetus-jdk8-hadoop2-unit-check/output
+ retention-days: 7
diff --git a/.gitignore b/.gitignore
index 666771f7e251..9ab7a972d7ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,8 @@
.DS_Store
.classpath
/build
-/.idea/
+.idea/*
+!.idea/vcs.xml
/logs
*target/
*.orig
@@ -24,3 +25,4 @@ linklint/
tmp
**/.flattened-pom.xml
.vscode/
+**/__pycache__
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 000000000000..b2aa0751c813
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/CHANGES.md b/CHANGES.md
index debb62e9a2ad..458f125200be 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -18,6 +18,314 @@
-->
# HBASE Changelog
+## Release 2.6.5 - 2026-03-20
+
+
+
+### IMPROVEMENTS:
+
+| JIRA | Summary | Priority | Component |
+|:---- |:---- | :--- |:---- |
+| [HBASE-30003](https://issues.apache.org/jira/browse/HBASE-30003) | Upgrade deprecated GitHub Actions versions for branch-2.x | Major | build |
+| [HBASE-30002](https://issues.apache.org/jira/browse/HBASE-30002) | Rewrite TestExportSnapshot related UTs | Major | mapreduce, test |
+| [HBASE-29999](https://issues.apache.org/jira/browse/HBASE-29999) | Update the download links in the README | Minor | . |
+| [HBASE-29994](https://issues.apache.org/jira/browse/HBASE-29994) | Separate backwards compatibility checks to a new jenkins job | Major | jenkins, scripts |
+| [HBASE-29981](https://issues.apache.org/jira/browse/HBASE-29981) | Upgrade hbase-endpoint to use junit5 | Major | test |
+| [HBASE-29927](https://issues.apache.org/jira/browse/HBASE-29927) | Upgrade hbase-external-blockcache to use junit5 | Major | test |
+| [HBASE-29988](https://issues.apache.org/jira/browse/HBASE-29988) | Upgrade hbase-archetypes to use junit5 | Major | test |
+| [HBASE-29969](https://issues.apache.org/jira/browse/HBASE-29969) | Bump lz4-java 1.10.4 | Major | dependencies |
+| [HBASE-29982](https://issues.apache.org/jira/browse/HBASE-29982) | Upgrade TestTags to JUnit5 and polish the code | Major | test |
+| [HBASE-29949](https://issues.apache.org/jira/browse/HBASE-29949) | Downgrade info log in GlobalMetricRegistriesAdapter | Major | metrics |
+| [HBASE-29978](https://issues.apache.org/jira/browse/HBASE-29978) | Remove redundant imports in regionserver.jsp file | Trivial | UI |
+| [HBASE-29954](https://issues.apache.org/jira/browse/HBASE-29954) | Support magic links to PR and JIRA in IDEA | Minor | community |
+| [HBASE-29980](https://issues.apache.org/jira/browse/HBASE-29980) | Polish jenkinsfiles after splitting integration test out | Major | jenkins |
+| [HBASE-28601](https://issues.apache.org/jira/browse/HBASE-28601) | Enable setting memstore on-heap sizes in bytes | Major | regionserver |
+| [HBASE-29966](https://issues.apache.org/jira/browse/HBASE-29966) | Fix race in FlushRegionProcedure and rewrite TestAcidGuarantees | Major | proc-v2, test |
+| [HBASE-29979](https://issues.apache.org/jira/browse/HBASE-29979) | Remove JUnit5 related dependencies in hbase-protocol-shaded | Major | test |
+| [HBASE-29967](https://issues.apache.org/jira/browse/HBASE-29967) | Upgrade hbase-backup to use junit5 | Major | backup&restore, test |
+| [HBASE-29938](https://issues.apache.org/jira/browse/HBASE-29938) | Upgrade hbase-it to use junit5 | Major | integration tests, test |
+| [HBASE-29940](https://issues.apache.org/jira/browse/HBASE-29940) | GC Collector stats can't be displayed properly in JDK21 | Major | UI |
+| [HBASE-29939](https://issues.apache.org/jira/browse/HBASE-29939) | Upgrade hbase-logging to use junit5 | Major | logging, test |
+| [HBASE-29937](https://issues.apache.org/jira/browse/HBASE-29937) | Upgrade hbase-metrics-api to use junit5 | Major | metrics, test |
+| [HBASE-29934](https://issues.apache.org/jira/browse/HBASE-29934) | Quota Info in Table Attributes should display more clearly | Major | Quotas, UI |
+| [HBASE-29935](https://issues.apache.org/jira/browse/HBASE-29935) | Update copyright notices year to 2026 | Minor | documentation |
+| [HBASE-29926](https://issues.apache.org/jira/browse/HBASE-29926) | Upgrade hbase-hadoop-compat to use junit5 | Major | test |
+| [HBASE-29932](https://issues.apache.org/jira/browse/HBASE-29932) | Upgrade hbase-http to use junit5 | Major | test |
+| [HBASE-23644](https://issues.apache.org/jira/browse/HBASE-23644) | Thrift2 DemoClient.py is not running | Minor | . |
+| [HBASE-29457](https://issues.apache.org/jira/browse/HBASE-29457) | thrift1/DemoClient.py is not running | Minor | . |
+| [HBASE-29910](https://issues.apache.org/jira/browse/HBASE-29910) | Upgrade hbase-client to use junit5 | Major | Client, test |
+| [HBASE-29925](https://issues.apache.org/jira/browse/HBASE-29925) | TestCheckTestClasses fails on branch-2.x with JDK8 | Major | test |
+| [HBASE-29874](https://issues.apache.org/jira/browse/HBASE-29874) | Removing the useless parameters from ScanQueryMatcher.isCellTTLExpired | Major | . |
+| [HBASE-29919](https://issues.apache.org/jira/browse/HBASE-29919) | Test case TestSecureIPC#testRpcServerDisallowFallbackToSimpleAuth failed | Major | test |
+| [HBASE-29911](https://issues.apache.org/jira/browse/HBASE-29911) | Upgrade hbase-examples to use junit5 | Major | test |
+| [HBASE-29871](https://issues.apache.org/jira/browse/HBASE-29871) | During WAL write times out add DataNode address in. the exception message | Minor | Filesystem Integration, io |
+| [HBASE-29902](https://issues.apache.org/jira/browse/HBASE-29902) | Upgrade hbase-thrift to use junit5 | Major | test, Thrift |
+| [HBASE-29887](https://issues.apache.org/jira/browse/HBASE-29887) | Upgrade hbase-hbtop to use junit5 | Major | hbtop, test |
+| [HBASE-29721](https://issues.apache.org/jira/browse/HBASE-29721) | Add validation for Mutations without column families | Minor | Client |
+| [HBASE-29901](https://issues.apache.org/jira/browse/HBASE-29901) | Upgrade hbase-zookeeper to use junit5 | Major | test, Zookeeper |
+| [HBASE-29898](https://issues.apache.org/jira/browse/HBASE-29898) | Upgrade hbase-replication to use junit5 | Major | Replication, test |
+| [HBASE-29903](https://issues.apache.org/jira/browse/HBASE-29903) | hbtop should display default replica id | Major | hbtop |
+| [HBASE-29885](https://issues.apache.org/jira/browse/HBASE-29885) | Enable Disabled UT TestNamespacesInstanceResource.testInvalidNamespacePostsAndPuts | Minor | REST, test |
+| [HBASE-29900](https://issues.apache.org/jira/browse/HBASE-29900) | Correct logger initialization under hbase-procedure | Major | proc-v2, test |
+| [HBASE-29844](https://issues.apache.org/jira/browse/HBASE-29844) | Upgrade hbase-metrics to use junit5 | Major | metrics, test |
+| [HBASE-29562](https://issues.apache.org/jira/browse/HBASE-29562) | Add RegionServer Metrics for excluded DataNodes | Minor | metrics |
+| [HBASE-29879](https://issues.apache.org/jira/browse/HBASE-29879) | Upgrade hbase-procedure to use junit5 | Major | . |
+| [HBASE-29876](https://issues.apache.org/jira/browse/HBASE-29876) | Upgrade hbase-shell to use junit5 | Major | shell, test |
+| [HBASE-25508](https://issues.apache.org/jira/browse/HBASE-25508) | Add a python example of using the thrift proxy in thrift-over-http mode | Minor | Thrift |
+| [HBASE-29858](https://issues.apache.org/jira/browse/HBASE-29858) | Upgrade hbase-rest to use junit5 | Major | test |
+| [HBASE-29867](https://issues.apache.org/jira/browse/HBASE-29867) | Promote some medium tests to large tests | Major | test |
+| [HBASE-29866](https://issues.apache.org/jira/browse/HBASE-29866) | Generate job summary for our yetus check github action | Major | build |
+| [HBASE-29845](https://issues.apache.org/jira/browse/HBASE-29845) | Description of the hbase:slowlog is not displayed correctly | Major | UI |
+| [HBASE-29820](https://issues.apache.org/jira/browse/HBASE-29820) | Bump the syntax of velocity template to align with velocity 2.x syntax | Minor | . |
+| [HBASE-29828](https://issues.apache.org/jira/browse/HBASE-29828) | Upgrade TestIPC related tests to junit5 | Major | rpc, test |
+| [HBASE-29821](https://issues.apache.org/jira/browse/HBASE-29821) | Fix maven-source-plugin duplicate jar failure | Minor | . |
+| [HBASE-29819](https://issues.apache.org/jira/browse/HBASE-29819) | Upgrade hbase-asyncfs to use junit5 | Major | Filesystem Integration, test |
+| [HBASE-29817](https://issues.apache.org/jira/browse/HBASE-29817) | Stop retrying on DoNotRetryIOException when waiting procedure result | Major | Admin, asyncclient |
+| [HBASE-29727](https://issues.apache.org/jira/browse/HBASE-29727) | Introduce a String pool for repeating filename, region and cf string fields in BlockCacheKey | Major | . |
+| [HBASE-29808](https://issues.apache.org/jira/browse/HBASE-29808) | Simplify backup history retrieval | Minor | backup&restore |
+| [HBASE-29810](https://issues.apache.org/jira/browse/HBASE-29810) | Polish TestFileChangeWatcher | Major | test |
+| [HBASE-29796](https://issues.apache.org/jira/browse/HBASE-29796) | Allow sleepForRetry replication config to be overridden by replication peers | Minor | Replication |
+| [HBASE-29794](https://issues.apache.org/jira/browse/HBASE-29794) | Only exclude tests when its failure rate above a threshold | Major | flakies, jenkins |
+| [HBASE-29706](https://issues.apache.org/jira/browse/HBASE-29706) | Modify table with lazy mode should pass if coprocessors have not changed | Major | . |
+| [HBASE-29732](https://issues.apache.org/jira/browse/HBASE-29732) | Add hbase.rs.evictblocksonsplit to UI and CacheConfig logs | Major | BlockCache |
+| [HBASE-29729](https://issues.apache.org/jira/browse/HBASE-29729) | Add per-region table descriptor hash to RegionServer JMX metrics | Minor | metrics, regionserver |
+| [HBASE-29767](https://issues.apache.org/jira/browse/HBASE-29767) | Fix IOTimePerHit NaN issue in BucketCacheStats | Minor | BlockCache |
+| [HBASE-29645](https://issues.apache.org/jira/browse/HBASE-29645) | AsyncBufferedMutatorImpl concurrency improvement | Major | Client |
+| [HBASE-29731](https://issues.apache.org/jira/browse/HBASE-29731) | Add L1 and L2 cache hit/miss caching metrics | Trivial | BlockCache |
+| [HBASE-29725](https://issues.apache.org/jira/browse/HBASE-29725) | Refactor the testScan method of TestDefaultMemStore | Minor | in-memory-compaction |
+| [HBASE-29714](https://issues.apache.org/jira/browse/HBASE-29714) | Increase DEFAULT\_RS\_REMOTE\_PROC\_RETRY\_LIMIT to 10 | Major | proc-v2 |
+| [HBASE-29033](https://issues.apache.org/jira/browse/HBASE-29033) | Add a shell command for inspecting the state of enable/disable\_rpc\_throttle | Major | Quotas, shell |
+| [HBASE-29703](https://issues.apache.org/jira/browse/HBASE-29703) | Remove duplicate calls to withNextBlockOnDiskSize | Minor | BucketCache |
+| [HBASE-29473](https://issues.apache.org/jira/browse/HBASE-29473) | Obtain target cluster's token for cross clusters job | Major | . |
+
+
+### BUG FIXES:
+
+| JIRA | Summary | Priority | Component |
+|:---- |:---- | :--- |:---- |
+| [HBASE-29955](https://issues.apache.org/jira/browse/HBASE-29955) | HMaster getting aborted due to NPE while creating snapshot for invalid table name | Major | snapshots |
+| [HBASE-29987](https://issues.apache.org/jira/browse/HBASE-29987) | Replication position corruption when WAL file switch detected in ReplicationSourceWALReader run loop | Minor | Replication, wal, Zookeeper |
+| [HBASE-29800](https://issues.apache.org/jira/browse/HBASE-29800) | WAL logs are unprotected during first full backup | Major | backup&restore |
+| [HBASE-29977](https://issues.apache.org/jira/browse/HBASE-29977) | TestFSUtils fails with class not found | Major | . |
+| [HBASE-29777](https://issues.apache.org/jira/browse/HBASE-29777) | Slow and Large Response RPC StartTime in SlowLog Operation Details page is incorrect | Major | . |
+| [HBASE-29834](https://issues.apache.org/jira/browse/HBASE-29834) | MILLIS\_BETWEEN\_NEXTS metric is not updated on branch-3+ | Minor | asyncclient, Client, scan |
+| [HBASE-29759](https://issues.apache.org/jira/browse/HBASE-29759) | TestAsyncTableScan fails with tracing assert error | Major | asyncclient, tracing |
+| [HBASE-29862](https://issues.apache.org/jira/browse/HBASE-29862) | Test case TestClearRegionBlockCache#testClearBlockCache failed | Major | BlockCache, test |
+| [HBASE-28913](https://issues.apache.org/jira/browse/HBASE-28913) | LoadBalancerPerformanceEvaluation fails with NPE | Major | tooling |
+| [HBASE-29907](https://issues.apache.org/jira/browse/HBASE-29907) | ROWCOL bloom filter + StoreScanner.trySkipToNextColumn can surface out-of-order cells, causing read failure “isDelete failed” | Blocker | Filters, Scanners |
+| [HBASE-29915](https://issues.apache.org/jira/browse/HBASE-29915) | Rewrite TestMultiRowResource and TestSchemaResource | Major | REST, test |
+| [HBASE-29917](https://issues.apache.org/jira/browse/HBASE-29917) | TestCheckTestClasses fails with JDK8 + hadoop3 | Major | test |
+| [HBASE-28985](https://issues.apache.org/jira/browse/HBASE-28985) | Fix memStoreSize metric for a table and add heap and off-heap size metrics | Minor | metrics |
+| [HBASE-29886](https://issues.apache.org/jira/browse/HBASE-29886) | list\_namespace will throw instance vars on non-persistent Java type warning | Minor | shell |
+| [HBASE-29846](https://issues.apache.org/jira/browse/HBASE-29846) | Fix backup history ordering | Minor | backup&restore |
+| [HBASE-29877](https://issues.apache.org/jira/browse/HBASE-29877) | Load Test Tool doesn't read with TIMELINE consistency, because it sets replica id explicitly | Major | test, util |
+| [HBASE-29859](https://issues.apache.org/jira/browse/HBASE-29859) | Initialization log for DataTieringManager is incorrect | Minor | regionserver |
+| [HBASE-29896](https://issues.apache.org/jira/browse/HBASE-29896) | Raw scan incorrectly skips cells expired by cell-level TTL | Minor | Scanners |
+| [HBASE-29870](https://issues.apache.org/jira/browse/HBASE-29870) | Correct the UI Column name from Stats to State in rsgroup.jsp | Major | UI |
+| [HBASE-29868](https://issues.apache.org/jira/browse/HBASE-29868) | Can not start mini dfs cluster when building against hadoop 3.3.x | Major | hadoop3, logging |
+| [HBASE-29857](https://issues.apache.org/jira/browse/HBASE-29857) | BucketCache fails to start when persistence file was written with empty cache | Critical | regionserver |
+| [HBASE-29831](https://issues.apache.org/jira/browse/HBASE-29831) | Region replica's can fall behind due to a NPE during processing | Minor | read replicas |
+| [HBASE-29860](https://issues.apache.org/jira/browse/HBASE-29860) | Fix NullPointerException on Maven site build | Blocker | build, site |
+| [HBASE-29854](https://issues.apache.org/jira/browse/HBASE-29854) | Add osgi annotations dependency when generating javadoc | Major | build, site |
+| [HBASE-29788](https://issues.apache.org/jira/browse/HBASE-29788) | Bump the version for Maven Project Info Reports Plugin | Major | build, pom, site |
+| [HBASE-29141](https://issues.apache.org/jira/browse/HBASE-29141) | Calculate default maxQueueLength call queues correctly | Major | master, regionserver |
+| [HBASE-29830](https://issues.apache.org/jira/browse/HBASE-29830) | Manage org.bouncycastle:bcutil-jdk18on version | Major | . |
+| [HBASE-29836](https://issues.apache.org/jira/browse/HBASE-29836) | Add org.bouncycastle:bcpkix-jdk18on as explicit test dependency to hbase-http | Major | test |
+| [HBASE-29783](https://issues.apache.org/jira/browse/HBASE-29783) | Fix flaky TestVerifyBucketCacheFile.testRetrieveFromFile test | Minor | . |
+| [HBASE-29144](https://issues.apache.org/jira/browse/HBASE-29144) | Client request fails for KERBEROS with RpcConnectionRegistry | Blocker | Client, rpc, security |
+| [HBASE-29802](https://issues.apache.org/jira/browse/HBASE-29802) | NPE when shutting down mini cluster cause tests hang | Major | mapreduce, test |
+| [HBASE-29795](https://issues.apache.org/jira/browse/HBASE-29795) | RegionServer abort because of NPE when closing compacted store file | Major | Compaction, regionserver |
+| [HBASE-29793](https://issues.apache.org/jira/browse/HBASE-29793) | TestDefaultHandlerUsageQuota fails 100% on flaky dashboard | Major | Quotas, test |
+| [HBASE-29797](https://issues.apache.org/jira/browse/HBASE-29797) | Should not create wal directory when creating WAL instance | Blocker | Region Assignment |
+| [HBASE-29775](https://issues.apache.org/jira/browse/HBASE-29775) | Allow inspecting log levels in Master UI in read-only mode | Minor | UI |
+| [HBASE-29742](https://issues.apache.org/jira/browse/HBASE-29742) | Compaction scan returns single cells instead of rows after 10MB | Major | Compaction |
+| [HBASE-29744](https://issues.apache.org/jira/browse/HBASE-29744) | Data loss scenario for WAL files belonging to RS added between backups | Major | backup&restore |
+| [HBASE-29526](https://issues.apache.org/jira/browse/HBASE-29526) | Dynamic configuration not working for coprocessor | Major | Coprocessors |
+| [HBASE-29771](https://issues.apache.org/jira/browse/HBASE-29771) | TestThreadHandlerUsageQuota fails on flaky dashboard | Major | Quotas |
+| [HBASE-29586](https://issues.apache.org/jira/browse/HBASE-29586) | Setting \`hbase.oldwals.cleaner.thread.size\` to negative value will throw IllegalArgumentException | Minor | . |
+| [HBASE-29760](https://issues.apache.org/jira/browse/HBASE-29760) | TestIncrementalBackup fails 100% on flaky dashboard | Major | backup&restore |
+| [HBASE-29501](https://issues.apache.org/jira/browse/HBASE-29501) | IOException in SerialReplicationChecker.canPush causes entries to be pushed out of order | Major | Replication |
+| [HBASE-28158](https://issues.apache.org/jira/browse/HBASE-28158) | Decouple RIT list management from TRSP invocation | Major | master, Region Assignment |
+| [HBASE-29709](https://issues.apache.org/jira/browse/HBASE-29709) | NPE may occur when compacting table via RawAsyncHBaseAdmin | Minor | asyncclient |
+| [HBASE-29698](https://issues.apache.org/jira/browse/HBASE-29698) | Correct log message in ReplicationSourceShipper.clearWALEntryBatch | Major | Replication |
+| [HBASE-29145](https://issues.apache.org/jira/browse/HBASE-29145) | Table Stats shows store file size as zero always for hbase:meta table | Major | UI |
+| [HBASE-29707](https://issues.apache.org/jira/browse/HBASE-29707) | Fix region cache % metrics miss calculation | Major | BucketCache |
+| [HBASE-29701](https://issues.apache.org/jira/browse/HBASE-29701) | Update README.txt in hbase-protocol-shaded | Minor | . |
+| [HBASE-29704](https://issues.apache.org/jira/browse/HBASE-29704) | Replace unsupported forkMode failsafe parameter in hbase-it | Major | integration tests |
+| [HBASE-29702](https://issues.apache.org/jira/browse/HBASE-29702) | Remove shade plugin from hbase-protocol-shaded | Minor | . |
+| [HBASE-29667](https://issues.apache.org/jira/browse/HBASE-29667) | The block priority is initialized as MULTI when the data block is first written into the BucketCache | Major | BucketCache |
+| [HBASE-29700](https://issues.apache.org/jira/browse/HBASE-29700) | Always close RPC servers in AbstractTestIPC | Minor | test |
+| [HBASE-29686](https://issues.apache.org/jira/browse/HBASE-29686) | Compatible issue of HFileOutputFormat2#configureRemoteCluster | Minor | . |
+| [HBASE-28839](https://issues.apache.org/jira/browse/HBASE-28839) | Exception handling during retrieval of bucket-cache from persistence. | Major | BucketCache |
+
+
+### SUB-TASKS:
+
+| JIRA | Summary | Priority | Component |
+|:---- |:---- | :--- |:---- |
+| [HBASE-29923](https://issues.apache.org/jira/browse/HBASE-29923) | Polish the nightly jenkins file | Major | jenkins, scripts |
+| [HBASE-29922](https://issues.apache.org/jira/browse/HBASE-29922) | Change hadoop check versions after supporting hadoop 3.4.3 | Major | scripts |
+| [HBASE-29921](https://issues.apache.org/jira/browse/HBASE-29921) | Bump default hadoop 3 version to 3.4.3 | Major | dependencies, hadoop3 |
+| [HBASE-29807](https://issues.apache.org/jira/browse/HBASE-29807) | Depend on jcip-annotations explicitly | Major | build, dependencies, hadoop3 |
+| [HBASE-29569](https://issues.apache.org/jira/browse/HBASE-29569) | Implement a built-in TieringValueProvider for parsing the date value from the rowkey | Minor | . |
+| [HBASE-29837](https://issues.apache.org/jira/browse/HBASE-29837) | Backport HBASE-27355 Separate meta read requests from master and client to branch-2 | Minor | . |
+| [HBASE-29596](https://issues.apache.org/jira/browse/HBASE-29596) | Migrate Canary Status Jamon page back to JSP | Major | UI |
+| [HBASE-29531](https://issues.apache.org/jira/browse/HBASE-29531) | Migrate RegionServer Status Jamon page back to JSP | Major | UI |
+| [HBASE-29223](https://issues.apache.org/jira/browse/HBASE-29223) | Migrate Master Status Jamon page back to JSP | Major | UI |
+| [HBASE-29568](https://issues.apache.org/jira/browse/HBASE-29568) | Allow for a configurable "grace period" when using Time Based Priority | Major | . |
+
+
+### OTHER:
+
+| JIRA | Summary | Priority | Component |
+|:---- |:---- | :--- |:---- |
+| [HBASE-29582](https://issues.apache.org/jira/browse/HBASE-29582) | Migrate Jamon pages back to JSP | Major | UI |
+| [HBASE-29985](https://issues.apache.org/jira/browse/HBASE-29985) | Bump org.apache.zookeeper:zookeeper from 3.8.4 to 3.8.6 | Major | dependabot, security, Zookeeper |
+| [HBASE-29971](https://issues.apache.org/jira/browse/HBASE-29971) | Upgrade to hbase-thirdparty 4.1.13 | Major | dependencies, thirdparty |
+| [HBASE-29893](https://issues.apache.org/jira/browse/HBASE-29893) | Add zizmor for GitHub Actions workflows security analysis | Major | build |
+| [HBASE-29930](https://issues.apache.org/jira/browse/HBASE-29930) | Separate packaging and integration check in nightly job to new jenkins job | Major | jenkins |
+| [HBASE-29454](https://issues.apache.org/jira/browse/HBASE-29454) | Update hbase-examples scripts to be compatible with Python 3 | Minor | . |
+| [HBASE-29928](https://issues.apache.org/jira/browse/HBASE-29928) | Bump io.airlift:aircompressor from 0.27 to 2.0.3 | Major | compression, dependabot, dependencies, security |
+| [HBASE-29916](https://issues.apache.org/jira/browse/HBASE-29916) | Correct alter\_async help text examples | Trivial | shell |
+| [HBASE-29897](https://issues.apache.org/jira/browse/HBASE-29897) | Bump org.apache.avro:avro from 1.11.4 to 1.11.5 | Major | dependabot, security |
+| [HBASE-29873](https://issues.apache.org/jira/browse/HBASE-29873) | Improve the job summary for unit check | Major | build, test |
+| [HBASE-29888](https://issues.apache.org/jira/browse/HBASE-29888) | GitHub Actions job summary should show which tests failed | Major | build |
+| [HBASE-29838](https://issues.apache.org/jira/browse/HBASE-29838) | Run Hadoop Check as a GitHub Action | Major | build |
+| [HBASE-29792](https://issues.apache.org/jira/browse/HBASE-29792) | Bump org.apache.logging.log4j:log4j-core from 2.17.2 to 2.25.3 | Major | dependabot, dependencies, logging, security |
+| [HBASE-29855](https://issues.apache.org/jira/browse/HBASE-29855) | Bump maven-site-plugin to 3.21.0 | Blocker | build, site |
+| [HBASE-29851](https://issues.apache.org/jira/browse/HBASE-29851) | Add more directories to yetus skip-dirs | Major | build |
+| [HBASE-29852](https://issues.apache.org/jira/browse/HBASE-29852) | GHA general check broken on branch-2\* | Major | build |
+| [HBASE-29829](https://issues.apache.org/jira/browse/HBASE-29829) | Pagination support for Hide Old Comments in PRs | Major | build |
+| [HBASE-29787](https://issues.apache.org/jira/browse/HBASE-29787) | Run Yetus General Checks as a GitHub Action | Major | build |
+| [HBASE-29791](https://issues.apache.org/jira/browse/HBASE-29791) | Backport 'HBASE-29761: The HBase UI's Debug Dump is not redacting sensitive information' to branch-2.6 | Critical | security, UI |
+| [HBASE-28804](https://issues.apache.org/jira/browse/HBASE-28804) | Implement asynchronous retrieval of bucket-cache data from persistence. | Major | BucketCache |
+| [HBASE-29743](https://issues.apache.org/jira/browse/HBASE-29743) | Fix typos in documentation for BulkLoadObserver | Trivial | documentation |
+| [HBASE-29740](https://issues.apache.org/jira/browse/HBASE-29740) | Upgrade lz4-java to 1.8.1+ | Major | security |
+| [HBASE-29695](https://issues.apache.org/jira/browse/HBASE-29695) | Fix typo in RestoreRequest's "Builder.withOvewrite()" method | Minor | backup&restore |
+| [HBASE-29724](https://issues.apache.org/jira/browse/HBASE-29724) | Backport missing changes of "HBASE-25334: TestRSGroupsFallback.testFallback is flaky" into branch-2 and branch-2.6 | Major | . |
+| [HBASE-29723](https://issues.apache.org/jira/browse/HBASE-29723) | Backport "HBASE-25282: Remove processingServers in DeadServer as we can get this information by Procedure of master" to branch-2.6 | Major | . |
+
+
+## Release 2.6.4 - 2025-11-10
+
+
+
+### NEW FEATURES:
+
+| JIRA | Summary | Priority | Component |
+|:---- |:---- | :--- |:---- |
+| [HBASE-28463](https://issues.apache.org/jira/browse/HBASE-28463) | Time Based Priority for BucketCache | Major | BucketCache |
+| [HBASE-28919](https://issues.apache.org/jira/browse/HBASE-28919) | Soft drop for destructive table actions | Major | master, snapshots |
+
+
+### IMPROVEMENTS:
+
+| JIRA | Summary | Priority | Component |
+|:---- |:---- | :--- |:---- |
+| [HBASE-29679](https://issues.apache.org/jira/browse/HBASE-29679) | Suppress stack trace in RpcThrottlingException | Minor | Quotas |
+| [HBASE-29663](https://issues.apache.org/jira/browse/HBASE-29663) | TimeBasedLimiters should support dynamic configuration refresh | Major | . |
+| [HBASE-29653](https://issues.apache.org/jira/browse/HBASE-29653) | Build fails on riscv64 due to os-maven-plugin not recognizing RISC-V architecture | Major | build |
+| [HBASE-29650](https://issues.apache.org/jira/browse/HBASE-29650) | Upgrade tomcat-jasper to 9.0.110 | Major | UI |
+| [HBASE-29637](https://issues.apache.org/jira/browse/HBASE-29637) | Implement ResourceCheckerJUnitListener for junit 5 | Major | test |
+| [HBASE-29649](https://issues.apache.org/jira/browse/HBASE-29649) | Un-deprecate preWALRestore and postWALRestore in RegionCoprocessorHost | Minor | Coprocessors |
+| [HBASE-29636](https://issues.apache.org/jira/browse/HBASE-29636) | Implement TimedOutTestsListener for junit 5 | Major | test |
+| [HBASE-29626](https://issues.apache.org/jira/browse/HBASE-29626) | Refactor server side scan metrics for Coproc hooks | Minor | . |
+| [HBASE-28440](https://issues.apache.org/jira/browse/HBASE-28440) | Add support for using mapreduce sort in HFileOutputFormat2 | Major | backup&restore |
+| [HBASE-29627](https://issues.apache.org/jira/browse/HBASE-29627) | Handle any block cache fetching errors when reading a block in HFileReaderImpl | Major | BlockCache |
+| [HBASE-29576](https://issues.apache.org/jira/browse/HBASE-29576) | Replicate HBaseClassTestRule functionality for Junit 5 | Major | test |
+| [HBASE-29612](https://issues.apache.org/jira/browse/HBASE-29612) | Remove HBaseTestingUtil.forceChangeTaskLogDir | Major | . |
+| [HBASE-29608](https://issues.apache.org/jira/browse/HBASE-29608) | Add test to make sure we do not have copy paste errors in the TAG value | Minor | test |
+| [HBASE-29610](https://issues.apache.org/jira/browse/HBASE-29610) | Add and use String constants for Junit 5 @Tag annotations | Minor | integration tests, test |
+| [HBASE-29573](https://issues.apache.org/jira/browse/HBASE-29573) | Fully load QuotaCache instead of reading individual rows on demand | Minor | . |
+| [HBASE-29571](https://issues.apache.org/jira/browse/HBASE-29571) | Fix Javadoc typo: 'repoen' should be 'reopen' | Trivial | . |
+| [HBASE-29575](https://issues.apache.org/jira/browse/HBASE-29575) | Do not limit surefire to Junit 4 | Major | test |
+| [HBASE-29496](https://issues.apache.org/jira/browse/HBASE-29496) | Fix Javadoc typo: 'DsiableTableProcedure' should be 'DisableTableProcedure' | Trivial | documentation |
+| [HBASE-29494](https://issues.apache.org/jira/browse/HBASE-29494) | Capture Scan RPC processing time and queuing time in Scan Metrics | Minor | . |
+| [HBASE-29479](https://issues.apache.org/jira/browse/HBASE-29479) | QuotaCache is not correctly populated until runs of QuotaRefresherChore | Minor | . |
+| [HBASE-29556](https://issues.apache.org/jira/browse/HBASE-29556) | Display HBCK and CatalogJanitor report errors properly on HBCK Report page | Major | UI |
+| [HBASE-29431](https://issues.apache.org/jira/browse/HBASE-29431) | Update the 'ExcludeDNs' information with the cause in RS UI | Major | UI |
+| [HBASE-29528](https://issues.apache.org/jira/browse/HBASE-29528) | Support for cellVisibility in Thrift interface | Minor | Thrift |
+| [HBASE-29290](https://issues.apache.org/jira/browse/HBASE-29290) | Include port number of Region Server in the Replication Status message | Minor | shell |
+| [HBASE-29469](https://issues.apache.org/jira/browse/HBASE-29469) | Add RPC throttling metrics to RegionServer for quota monitoring | Minor | metrics |
+| [HBASE-29508](https://issues.apache.org/jira/browse/HBASE-29508) | Define HBase specific TLS config properties for InfoServer | Major | . |
+| [HBASE-29477](https://issues.apache.org/jira/browse/HBASE-29477) | Make TableOutputCommitter Configurable for TableOutputFormat | Blocker | . |
+| [HBASE-29481](https://issues.apache.org/jira/browse/HBASE-29481) | Make TLS protocols and include cipher list configurable for HTTPS InfoServer | Major | security, UI |
+| [HBASE-15625](https://issues.apache.org/jira/browse/HBASE-15625) | Make minimum values configurable and smaller | Minor | . |
+| [HBASE-29467](https://issues.apache.org/jira/browse/HBASE-29467) | Redundant conditions in CostFunction.scale() method | Major | Balancer |
+| [HBASE-29450](https://issues.apache.org/jira/browse/HBASE-29450) | Bump org.apache.commons:commons-lang3 from 3.17.0 to 3.18.0 | Major | dependabot, dependencies, security |
+| [HBASE-29398](https://issues.apache.org/jira/browse/HBASE-29398) | Server side scan metrics for bytes read from FS vs Block cache vs memstore | Major | . |
+
+
+### BUG FIXES:
+
+| JIRA | Summary | Priority | Component |
+|:---- |:---- | :--- |:---- |
+| [HBASE-29662](https://issues.apache.org/jira/browse/HBASE-29662) | Reading data via TableSnapshotInputFormat should fail instead of reading no data if restore directory got deleted | Critical | snapshots |
+| [HBASE-29622](https://issues.apache.org/jira/browse/HBASE-29622) | Flaky Test : TestBackupDelete#testBackupDeleteUpdatesIncrementalBackupSet | Major | backup&restore |
+| [HBASE-29677](https://issues.apache.org/jira/browse/HBASE-29677) | Thread safety in QuotaRefresherChore | Minor | . |
+| [HBASE-29604](https://issues.apache.org/jira/browse/HBASE-29604) | BackupHFileCleaner uses flawed time based check | Critical | backup&restore |
+| [HBASE-29629](https://issues.apache.org/jira/browse/HBASE-29629) | Record the quota user name value on metrics for RpcThrottlingExceptions | Minor | Quotas |
+| [HBASE-29623](https://issues.apache.org/jira/browse/HBASE-29623) | Blocks for CFs with BlockCache disabled may still get cached on write or compaction | Major | BlockCache |
+| [HBASE-29550](https://issues.apache.org/jira/browse/HBASE-29550) | Reflection error in TestRSGroupsKillRS with Java 21 | Major | test |
+| [HBASE-29587](https://issues.apache.org/jira/browse/HBASE-29587) | Set Test category for TestSnapshotProcedureEarlyExpiration | Minor | snapshots |
+| [HBASE-29601](https://issues.apache.org/jira/browse/HBASE-29601) | Handle Junit 5 tests in TestCheckTestClasses | Major | test |
+| [HBASE-29602](https://issues.apache.org/jira/browse/HBASE-29602) | Add -Djava.security.manager=allow to JDK18+ surefire JVM flags | Major | integration tests, test |
+| [HBASE-29548](https://issues.apache.org/jira/browse/HBASE-29548) | Update ApacheDS to 2.0.0.AM27 and ldap-api to 2.1.7 | Major | test |
+| [HBASE-29577](https://issues.apache.org/jira/browse/HBASE-29577) | Fix NPE from RegionServerRpcQuotaManager when reloading configuration | Minor | . |
+| [HBASE-27157](https://issues.apache.org/jira/browse/HBASE-27157) | Potential race condition in WorkerAssigner | Minor | proc-v2 |
+| [HBASE-29566](https://issues.apache.org/jira/browse/HBASE-29566) | TestPrefetch.testPrefetchWithDelay seems flakey | Major | . |
+| [HBASE-29453](https://issues.apache.org/jira/browse/HBASE-29453) | NPE on CacheAwareLoadBalancer.balanceTable | Trivial | Balancer |
+| [HBASE-29540](https://issues.apache.org/jira/browse/HBASE-29540) | Unhandled IllegalArgumentException in HBase Web UI When Accessing table.jsp with Invalid Table Name | Minor | UI |
+| [HBASE-29558](https://issues.apache.org/jira/browse/HBASE-29558) | Broken hbase-shell no-cluster tests | Major | shell |
+| [HBASE-29570](https://issues.apache.org/jira/browse/HBASE-29570) | Set no watches on the node when recursively deleting the node and its child nodes | Minor | Zookeeper |
+| [HBASE-28881](https://issues.apache.org/jira/browse/HBASE-28881) | Setting \`hbase.master.procedure.threads\` to negative value doesn't break HMaster but clients cannot connect | Critical | master |
+| [HBASE-29549](https://issues.apache.org/jira/browse/HBASE-29549) | Mockito failures in TestServerCall with Java 21 | Major | test |
+| [HBASE-28866](https://issues.apache.org/jira/browse/HBASE-28866) | Setting \`hbase.oldwals.cleaner.thread.size\` to negative value will break HMaster and produce hard-to-diagnose logs | Critical | master |
+| [HBASE-29532](https://issues.apache.org/jira/browse/HBASE-29532) | NPE error when there is EOF for specific recover folder | Major | . |
+| [HBASE-29502](https://issues.apache.org/jira/browse/HBASE-29502) | RegionReplicaReplicationEndpoint fails to forward mutations when meta cache does not contain secondary replica locations | Major | read replicas |
+| [HBASE-29544](https://issues.apache.org/jira/browse/HBASE-29544) | Assertion errors in BackupAndRestoreThread are not causing IntegrationTestBackupRestore to fail | Major | integration tests |
+| [HBASE-29184](https://issues.apache.org/jira/browse/HBASE-29184) | The snapshot type for disabled table is incorrect when snapshot procedure is enabled | Major | snapshots |
+| [HBASE-29493](https://issues.apache.org/jira/browse/HBASE-29493) | TestBucketCacheRefCnt.testInBucketCache fails if block found after eviction | Minor | BucketCache |
+| [HBASE-29543](https://issues.apache.org/jira/browse/HBASE-29543) | TestFileChangeWatcher fails with Java 8 due to file modification time granularity issue | Minor | . |
+| [HBASE-29507](https://issues.apache.org/jira/browse/HBASE-29507) | IntegrationTestBackupRestore is failing because it cannot restore from backup directory | Major | . |
+| [HBASE-28951](https://issues.apache.org/jira/browse/HBASE-28951) | Handle simultaneous WAL splitting to recovered edits by multiple worker | Major | . |
+| [HBASE-29503](https://issues.apache.org/jira/browse/HBASE-29503) | IntegrationTestBackupRestore is passing even if an exception occurs in the thread(s) it creates | Major | integration tests |
+| [HBASE-29296](https://issues.apache.org/jira/browse/HBASE-29296) | Missing critical snapshot expiration checks | Critical | backup&restore, snapshots |
+| [HBASE-29463](https://issues.apache.org/jira/browse/HBASE-29463) | Bidirectional serial replication will block if a region’s last edit before rs crashed was from the peer cluster | Critical | Replication |
+| [HBASE-29482](https://issues.apache.org/jira/browse/HBASE-29482) | Bulkload fails with viewfs authentication error | Minor | . |
+| [HBASE-29472](https://issues.apache.org/jira/browse/HBASE-29472) | Fix splitting algorithms of RegionSplitter tool | Minor | util |
+| [HBASE-29447](https://issues.apache.org/jira/browse/HBASE-29447) | WAL Archives Cause Incremental Backup Failures | Major | backup&restore |
+| [HBASE-29474](https://issues.apache.org/jira/browse/HBASE-29474) | RegionSplitter.rollingSplit is broken | Major | . |
+| [HBASE-28589](https://issues.apache.org/jira/browse/HBASE-28589) | Server side DoNotRetryException not propagated to client | Critical | IPC/RPC |
+
+
+### SUB-TASKS:
+
+| JIRA | Summary | Priority | Component |
+|:---- |:---- | :--- |:---- |
+| [HBASE-29614](https://issues.apache.org/jira/browse/HBASE-29614) | Remove static final field modification in tests around Unsafe | Major | test |
+| [HBASE-29591](https://issues.apache.org/jira/browse/HBASE-29591) | Add hadoop 3.4.2 in hadoop check | Major | hadoop3, jenkins, scripts |
+| [HBASE-29592](https://issues.apache.org/jira/browse/HBASE-29592) | Add hadoop 3.4.2 in client integration tests | Major | hadoop3, jenkins, scripts |
+| [HBASE-29590](https://issues.apache.org/jira/browse/HBASE-29590) | Use hadoop 3.4.2 as default hadooop3 dependency | Major | dependencies, hadoop3 |
+| [HBASE-29427](https://issues.apache.org/jira/browse/HBASE-29427) | Merge all commits related to custom tiering into the feature branch | Major | . |
+| [HBASE-28467](https://issues.apache.org/jira/browse/HBASE-28467) | Integration of time-based priority caching into cacheOnRead read code paths. | Major | BucketCache |
+| [HBASE-28469](https://issues.apache.org/jira/browse/HBASE-28469) | Integration of time-based priority caching into compaction paths. | Major | . |
+| [HBASE-28535](https://issues.apache.org/jira/browse/HBASE-28535) | Implement a region server level configuration to enable/disable data-tiering | Major | BucketCache |
+| [HBASE-28468](https://issues.apache.org/jira/browse/HBASE-28468) | Integration of time-based priority caching logic into cache evictions. | Major | . |
+| [HBASE-28466](https://issues.apache.org/jira/browse/HBASE-28466) | Integration of time-based priority logic of bucket cache in prefetch functionality of HBase. | Major | BucketCache |
+| [HBASE-28505](https://issues.apache.org/jira/browse/HBASE-28505) | Implement enforcement to require Date Tiered Compaction for Time Range Data Tiering | Major | . |
+| [HBASE-28465](https://issues.apache.org/jira/browse/HBASE-28465) | Implementation of framework for time-based priority bucket-cache. | Major | . |
+
+
+### OTHER:
+
+| JIRA | Summary | Priority | Component |
+|:---- |:---- | :--- |:---- |
+| [HBASE-23671](https://issues.apache.org/jira/browse/HBASE-23671) | Upgrade to JUnit 5 | Major | Filesystem Integration, test |
+| [HBASE-29509](https://issues.apache.org/jira/browse/HBASE-29509) | Bump hbase-thirdparty to 4.1.12 | Major | dependencies, thirdparty |
+| [HBASE-29527](https://issues.apache.org/jira/browse/HBASE-29527) | Bump org.bouncycastle:bcpkix-jdk18on from 1.78 to 1.81 | Major | dependabot, dependencies, security |
+
+
## Release 2.6.3 - Unreleased (as of 2025-07-10)
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 000000000000..a168d77d5600
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,5 @@
+When in the hubspot-2.6 branch, or sub-branches of that branch, use mvn11 instead of mvn, and use the hadoop-3.0 maven profile
+
+When in the master branch, or sub-branches of that branch, use mvn17 instead of mvn, and do not use the hadoop-3.0 maven profile.
+
+Always run the spotless:apply maven target after making changes.
diff --git a/NOTICE.txt b/NOTICE.txt
index b48c5475c962..55b8b5ae2bc5 100755
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -1,5 +1,5 @@
Apache HBase
-Copyright 2007-2022 The Apache Software Foundation
+Copyright 2007-2026 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
diff --git a/README.md b/README.md
index 058472e1c070..16c85a260a63 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ under the License.
# Getting Start
To get started using HBase, the full documentation for this release can be found under the doc/ directory that accompanies this README. Using a browser, open the docs/index.html to view the project home page (or browse https://hbase.apache.org). The hbase '[book](https://hbase.apache.org/book.html)' has a 'quick start' section and is where you should being your exploration of the hbase project.
-The latest HBase can be downloaded from the [download page](https://hbase.apache.org/downloads.html).
+The latest HBase can be downloaded from the [download page](https://hbase.apache.org/downloads/).
We use mailing lists to send notice and discuss. The mailing lists and archives are listed [here](http://hbase.apache.org/mail-lists.html)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 6e062b7d1876..b1caf20a942c 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -16,6 +16,195 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-->
+# HBASE 2.6.5 Release Notes
+
+These release notes cover new developer and user-facing incompatibilities, important issues, features, and major improvements.
+
+
+---
+
+* [HBASE-29930](https://issues.apache.org/jira/browse/HBASE-29930) | *Major* | **Separate packaging and integration check in nightly job to new jenkins job**
+
+Introduced a new HBase-Integration-Test jenkins job to run packaging and integration test.
+
+
+---
+
+* [HBASE-28985](https://issues.apache.org/jira/browse/HBASE-28985) | *Minor* | **Fix memStoreSize metric for a table and add heap and off-heap size metrics**
+
+The table-level memStoreSize metric was incorrectly summing data size, heap size, and off-heap size together, while the same metric at the region and region server levels reported only data size. This has been fixed so that memStoreSize now consistently reports data size at all levels.
+
+Two new metrics have been added at both the table and region levels:
+- memStoreHeapSize: on-heap memstore size
+- memStoreOffHeapSize: off-heap memstore size
+
+
+---
+
+* [HBASE-29877](https://issues.apache.org/jira/browse/HBASE-29877) | *Major* | **Load Test Tool doesn't read with TIMELINE consistency, because it sets replica id explicitly**
+
+New parameter for HBase LTT "--timeline": Use TIMELINE consistency in read operations.
+
+
+---
+
+* [HBASE-29569](https://issues.apache.org/jira/browse/HBASE-29569) | *Minor* | **Implement a built-in TieringValueProvider for parsing the date value from the rowkey**
+
+This introduces a regex based built-in tiering value provider for parsing dates directly from the rowkey portion of Cells. enabling time-based priority comparison. The implementation utilizes a configurable regular expression and date format to isolate a date substring within the RowKey, returning the parsed epoch time in milliseconds.
+
+Usage:
+This feature is controlled via table-level configuration properties. To utilize this provider, specify the class in the TIERING\_VALUE\_PROVIDER property and define the
+
+Configuration properties :
+TIERING\_KEY\_DATE\_PATTERN: Regex pattern for date extraction.
+TIERING\_KEY\_DATE\_FORMAT: Expected date format.
+TIERING\_KEY\_DATE\_GROUP: The target regex extract group.
+
+Example using hbase shell:
+
+-----
+hbase(main):003:0\> alter 'orders', {NAME =\> 'cf1',
+ CONFIGURATION =\> {'hbase.hstore.datatiering.type' =\> 'CUSTOM',
+ 'TIERING\_KEY\_DATE\_PATTERN' =\> '\_(\\\\d{4}-\\\\d{2}-\\\\d{2})\_',
+ 'TIERING\_KEY\_DATE\_FORMAT' =\> 'yyyy-MM-dd',
+ 'TIERING\_KEY\_DATE\_GROUP' =\> '1',
+ 'hbase.hstore.datatiering.hot.age.millis' =\> '604800000',
+ 'hbase.hstore.engine.class' =\> 'org.apache.hadoop.hbase.regionserver.CustomTieredStoreEngine',
+ 'hbase.hstore.compaction.date.tiered.custom.age.limit.millis' =\> '604800000'
+ }
+}
+-----
+
+Note: Please ensure strict validation of regex patterns and date formats to ensure accurate parsing.
+
+
+---
+
+* [HBASE-29837](https://issues.apache.org/jira/browse/HBASE-29837) | *Minor* | **Backport HBASE-27355 Separate meta read requests from master and client to branch-2**
+
+Dispatch the client's meta read request and the master's meta read request to different processing queues. Introduce a new configuration hbase.ipc.server.metacallqueue.handler.factor to determine the size of the meta request processing queue.
+
+
+---
+
+* [HBASE-29141](https://issues.apache.org/jira/browse/HBASE-29141) | *Major* | **Calculate default maxQueueLength call queues correctly**
+
+The default limit for RPC callqueue length was too high previously. The default was approximately the number of RPC handlers ^ 2 (squared), and is now approximately 10 \* number of RPC handlers. The length can still be overridden with hbase.ipc.server.max.callqueue.length.
+
+
+---
+
+* [HBASE-29144](https://issues.apache.org/jira/browse/HBASE-29144) | *Blocker* | **Client request fails for KERBEROS with RpcConnectionRegistry**
+
+SaslClientAuthenticationProviders and SaslServerAuthenticationProviders are not singleton now.
+
+As you are free to connect to different HBase clusters which have different authentication configurations from a single process, it does not make sense to let them share the same SaslClientAuthenticationProviders. Now we will create a SaslClientAuthenticationProviders for every Connection instance, even if you pass the same Configuration object when calling ConnectionFactory.createConnection.
+
+For SaslServerAuthenticationProviders, typically we will only initialize it once in production even if it is not singleton as we will only start a single service(like master or region server) in a process, making it not singleton can also benefit UTs as we will start multiple services when starting a mini cluster.
+
+
+---
+
+* [HBASE-29582](https://issues.apache.org/jira/browse/HBASE-29582) | *Major* | **Migrate Jamon pages back to JSP**
+
+Jamon is almost dead so in this issue, we moved our status page back to JSP, which is also old but a standard in Java EE that not easy to be dead.
+
+See https://lists.apache.org/thread/0c9to6rxzbf5f2x6t0x20408n15rdvmt for more details.
+
+
+---
+
+* [HBASE-29796](https://issues.apache.org/jira/browse/HBASE-29796) | *Minor* | **Allow sleepForRetry replication config to be overridden by replication peers**
+
+Setting a PeerConfig configuration value beginning with "replication.source" will override the value in the ReplicationSource for only that peer.
+
+If the default value for "replication.source.sleepforretries" is 1000 and there are two peers, '0' and '1', running "update\_peer\_config '0', CONFIG =\> { "replication.source.sleepforretries" =\> "500" }" will result in '0' using a value of 500 and '1' using the default value of 1000.
+
+
+---
+
+* [HBASE-29794](https://issues.apache.org/jira/browse/HBASE-29794) | *Major* | **Only exclude tests when its failure rate above a threshold**
+
+Now we will only exclude a test from nightly and pre commit build when its failure rate on flakydashboard is above 20% and have been run for at least 10 times.
+
+
+---
+
+* [HBASE-29526](https://issues.apache.org/jira/browse/HBASE-29526) | *Major* | **Dynamic configuration not working for coprocessor**
+
+This change fixed the dynamic configuration for coprocessor.
+
+
+---
+
+* [HBASE-29729](https://issues.apache.org/jira/browse/HBASE-29729) | *Minor* | **Add per-region table descriptor hash to RegionServer JMX metrics**
+
+Adds a tableDescriptorHash metric to region JMX output, exposing a SHA-256 hash of the region's current table descriptor. This enables operators to track which regions have adopted new descriptors during lazy table modifications, supporting progressive canary rollouts without maintaining external state. The hash is computed once at region open and cached for the region's lifetime.
+
+
+---
+
+* [HBASE-29740](https://issues.apache.org/jira/browse/HBASE-29740) | *Major* | **Upgrade lz4-java to 1.8.1+**
+
+Upgrade lz4-java to 1.10.1 for addressing CVE‐2025‐12183 and CVE-2025-66566.
+
+
+---
+
+* [HBASE-29695](https://issues.apache.org/jira/browse/HBASE-29695) | *Minor* | **Fix typo in RestoreRequest's "Builder.withOvewrite()" method**
+
+fixed typo of an internal API by replacing withOvewrite with withOverwrite
+
+
+
+# HBASE 2.6.4 Release Notes
+
+These release notes cover new developer and user-facing incompatibilities, important issues, features, and major improvements.
+
+
+---
+
+* [HBASE-29663](https://issues.apache.org/jira/browse/HBASE-29663) | *Major* | **TimeBasedLimiters should support dynamic configuration refresh**
+
+You can now refresh TimeBasedRateLimiter configurations dynamically with a call to the HBase shell's update\_all\_configs
+
+
+---
+
+* [HBASE-29573](https://issues.apache.org/jira/browse/HBASE-29573) | *Minor* | **Fully load QuotaCache instead of reading individual rows on demand**
+
+Each RegionServer now always caches the full contents of the hbase:quota table. If you have a very large quota table, this could cause excessive memory usage.
+
+
+---
+
+* [HBASE-28463](https://issues.apache.org/jira/browse/HBASE-28463) | *Major* | **Time Based Priority for BucketCache**
+
+This introduces time based priority for blocks in the BucketCache. It's disabled by default. Allows for defining an age threshold at individual column family configuration, whereby blocks older than this configured threshold would be targeted first for eviction. Blocks from column families that don't define the age threshold wouldn't be evaluated by the time based priority, and would only be evicted following the pre-existing LRU eviction logic.
+
+To enable it, first set the hbase.regionserver.datatiering.enable property to true in the RegionServer configuration. Then, for each table column family where time based priority behaviour is desired, add the following properties to the related column families configurations:
+- hbase.hstore.datatiering.type -\> TIME\_RANGE or CUSTOM
+- hbase.hstore.datatiering.hot.age.millis -\> A milliseconds age value (defaults to 7 Days or 604800000 milliseconds)
+- hbase.hstore.engine.class -\> org.apache.hadoop.hbase.regionserver.DateTieredStoreEngine or org.apache.hadoop.hbase.regionserver.CustomTieredStoreEngine
+
+The TIME\_RANGE value for hbase.hstore.datatiering.type will rely on cells timestamps for calculating the block age to be compared against the hbase.hstore.datatiering.hot.age.millis threshold age to decide on the block priority. This option requires that org.apache.hadoop.hbase.regionserver.DateTieredStoreEngine be defined as the hbase.hstore.engine.class. This is to enable date tiered compaction, so that data can be placed at separate files, according to the cells timestamps and the age threshold.
+
+The CUSTOM value for hbase.hstore.datatiering.type allows for defining custom logic to identify the age of cells that should be compared against the threshold age defined in the hbase.hstore.datatiering.hot.age.millis property. This option requires that org.apache.hadoop.hbase.regionserver.CustomTieredStoreEngine be defined as the hbase.hstore.engine.class. This is to enable the custom tiered compaction, so that data can be placed at separate files, according to the custom logic for defining the cell age to be compared against the age threshold. The custom logic for defining cell age should be provided as implementations of the CustomTieredCompactor.TieringValueProvider interface, and should be specified as the value of the hbase.hstore.custom-tiering-value.provider.class.
+
+Additionally, a built-in implementation of CustomTieredCompactor.TieringValueProvider is provided and set by default when the CUSTOM value for hbase.hstore.datatiering.type is in use. This assumes a custom column qualifier value to contain a long timestamp to be used as the cell age to be compared against the configured age threshold. This column qualifier should be configured as the TIERING\_CELL\_QUALIFIER property in the given column family configuration.
+
+Note that major compaction needs to be completed on the related tables once the feature is configured properly at the related column families configurations.
+
+
+---
+
+* [HBASE-15625](https://issues.apache.org/jira/browse/HBASE-15625) | *Minor* | **Make minimum values configurable and smaller**
+
+Introduced a new configuration \`hbase.regionserver.free.heap.min.memory.size\`.
+This configuration allows users to specify the minimum required amount of free heap memory using a human-readable format (e.g., 512m, 4g). By default, it remains consistent with the previous behavior, reserving 20% of the total heap size as free memory. This new option helps modern deployments with large heap sizes fine-tune memory usage more aggressively for MemStore and block cache configurations.
+
+
+
# HBASE 2.6.3 Release Notes
These release notes cover new developer and user-facing incompatibilities, important issues, features, and major improvements.
diff --git a/build-scripts/prepare_environment.sh b/build-scripts/prepare_environment.sh
new file mode 100755
index 000000000000..65842dcd4d17
--- /dev/null
+++ b/build-scripts/prepare_environment.sh
@@ -0,0 +1,97 @@
+#
+# Generates the appropriate environment vars so that we:
+# - build against the right version of hadoop, and properly set up maven
+# - generate the correct maven version based on the branches
+# - upload RPMs with the correct release based on the branch, and to the right yum repo
+#
+# Since we need to distribute .blazar.yaml to all sub-modules of the project, we define our constants once
+# in this script which can be re-used by every .blazar.yaml.
+#
+set -ex
+printenv
+
+# We base the expected main branch and resulting maven version for clients on the hbase minor version
+# The reason for this is hbase re-branches for each minor release (2.4, 2.5, 2.6, etc). At each re-branch
+# the histories diverge. So we'll need to create our own fork of each new minor release branch.
+# The convention is a fork named "hubspot-$minorVersion", and the maven coordinates "$minorVersion-hubspot-SNAPSHOT"
+MINOR_VERSION="2.6"
+MAIN_BRANCH="hubspot-${MINOR_VERSION}"
+
+#
+# Validate inputs from blazar
+#
+
+if [ -z "$WORKSPACE" ]; then
+ echo "Missing env var \$WORKSPACE"
+ exit 1
+fi
+if [ -z "$GIT_BRANCH" ]; then
+ echo "Missing env var \$GIT_BRANCH"
+ exit 1
+fi
+if [ -z "$BUILD_COMMAND_RC_FILE" ]; then
+ echo "Missing env var \$BUILD_COMMAND_RC_FILE"
+ exit 1
+fi
+
+#
+# Extract current hbase version from root pom.xml
+#
+
+# the pom.xml has an invalid xml namespace, so just remove that so xmllint can parse it.
+cat $WORKSPACE/pom.xml | sed '2 s/xmlns=".*"//g' > pom.xml.tmp
+HBASE_VERSION=$(echo "cat /project/properties/revision/text()" | xmllint --nocdata --shell pom.xml.tmp | sed '1d;$d')
+rm pom.xml.tmp
+
+# sanity check that we've got some that looks right. it wouldn't be the end of the world if we got it wrong, but
+# will help avoid confusion.
+if [[ ! "$HBASE_VERSION" =~ 2\.[0-9]+\.[0-9]+ ]]; then
+ echo "Unexpected HBASE_Version extracted from pom.xml. Got $HBASE_VERSION but expected a string like '2.4.3', with 3 numbers separated by decimals, the first number being 2."
+ exit 1
+fi
+
+#
+# Generate branch-specific env vars
+# We are going to generate the maven version and the RPM release here:
+# - For the maven version, we need to special case our main branch
+# - For RPM, we want our final version to be:
+# main branch: {hbase_version}-hs.{build_number}.el6
+# other branches: {hbase_version}-hs~{branch_name}.{build_number}.el6, where branch_name substitutes underscore for non-alpha-numeric characters
+#
+
+echo "Git branch $GIT_BRANCH. Detecting appropriate version override and RPM release."
+
+RELEASE="hs"
+
+if [[ "$GIT_BRANCH" = "$MAIN_BRANCH" ]]; then
+ SET_VERSION="${MINOR_VERSION}-hubspot-SNAPSHOT"
+ REPO_NAME="AnyLinuxVersion_hs-hbase"
+elif [[ "$GIT_BRANCH" != "hubspot" ]]; then
+ SET_VERSION="${MINOR_VERSION}-${GIT_BRANCH}-SNAPSHOT"
+ RELEASE="${RELEASE}~${GIT_BRANCH//[^[:alnum:]]/_}"
+ REPO_NAME="AnyLinuxVersion_hs-hbase-develop"
+else
+ echo "Invalid git branch $GIT_BRANCH"
+ exit 1
+fi
+
+RELEASE="${RELEASE}.${BUILD_NUMBER}"
+FULL_BUILD_VERSION="${HBASE_VERSION}-${RELEASE}"
+
+# SET_VERSION is not the most intuitive name, but it's required for set-maven-versions script
+write-build-env-var SET_VERSION "$SET_VERSION"
+write-build-env-var HBASE_VERSION "$HBASE_VERSION"
+write-build-env-var PKG_RELEASE "$RELEASE"
+write-build-env-var FULL_BUILD_VERSION "$FULL_BUILD_VERSION"
+write-build-env-var REPO_NAME "$REPO_NAME"
+# Adding this value as versioninfo.version ensures we have the same value as would normally
+# show up in a non-hubspot hbase build. Otherwise due to set-maven-versions we'd end up
+# with 2.6-hubspot-SNAPSHOT which is not very useful as a point of reference.
+# Another option would be to pass in our FULL_BUILD_VERSION but that might cause some funniness
+# with the expectations in VersionInfo.compareVersion().
+write-build-env-var MAVEN_BUILD_ARGS "$MAVEN_BUILD_ARGS -Dversioninfo.version=$HBASE_VERSION"
+
+echo "Building HBase version $HBASE_VERSION"
+echo "Will deploy to nexus with version $SET_VERSION"
+echo "Will create rpm with version $FULL_BUILD_VERSION"
+echo "Will run maven with extra args $MAVEN_BUILD_ARGS"
diff --git a/dev-support/Jenkinsfile b/dev-support/Jenkinsfile
index 4bc418017c0a..f22e67d04e83 100644
--- a/dev-support/Jenkinsfile
+++ b/dev-support/Jenkinsfile
@@ -38,7 +38,6 @@ pipeline {
OUTPUT_DIR_RELATIVE_JDK8_HADOOP3 = 'output-jdk8-hadoop3'
OUTPUT_DIR_RELATIVE_JDK11_HADOOP3 = 'output-jdk11-hadoop3'
OUTPUT_DIR_RELATIVE_JDK17_HADOOP3 = 'output-jdk17-hadoop3'
- OUTPUT_DIR_RELATIVE_JDK17_HADOOP3_BACKWARDS = 'output-jdk17-hadoop3-backwards'
PROJECT = 'hbase'
PROJECT_PERSONALITY = 'https://raw.githubusercontent.com/apache/hbase/master/dev-support/hbase-personality.sh'
@@ -58,9 +57,6 @@ pipeline {
ASF_NIGHTLIES = 'https://nightlies.apache.org'
ASF_NIGHTLIES_BASE_ORI = "${ASF_NIGHTLIES}/hbase/${JOB_NAME}/${BUILD_NUMBER}"
ASF_NIGHTLIES_BASE = "${ASF_NIGHTLIES_BASE_ORI.replaceAll(' ', '%20')}"
- // These are dependent on the branch
- HADOOP3_VERSIONS = "3.3.5,3.3.6,3.4.0,3.4.1"
- HADOOP3_DEFAULT_VERSION = "3.4.1"
}
parameters {
booleanParam(name: 'USE_YETUS_PRERELEASE', defaultValue: false, description: '''Check to use the current HEAD of apache/yetus rather than our configured release.
@@ -85,7 +81,7 @@ pipeline {
// can't just do a simple echo or the directory won't be created. :(
sh '''#!/usr/bin/env bash
echo "Make sure we have a directory for downloading dependencies: $(pwd)"
-'''
+ '''
}
sh '''#!/usr/bin/env bash
set -e
@@ -127,77 +123,8 @@ pipeline {
}
stash name: 'yetus', includes: "yetus-*/*,yetus-*/**/*,tools/personality.sh"
}
- }
- stage ('hadoop 2 cache') {
- environment {
- HADOOP2_VERSION="2.10.2"
- }
- steps {
- // directory must be unique for each parallel stage, because jenkins runs them in the same workspace :(
- dir('downloads-hadoop-2') {
- sh '''#!/usr/bin/env bash
- echo "Make sure we have a directory for downloading dependencies: $(pwd)"
-'''
- }
- sh '''#!/usr/bin/env bash
- set -e
- echo "Ensure we have a copy of Hadoop ${HADOOP2_VERSION}"
- "${WORKSPACE}/component/dev-support/jenkins-scripts/cache-apache-project-artifact.sh" \
- --working-dir "${WORKSPACE}/downloads-hadoop-2" \
- --keys 'https://downloads.apache.org/hadoop/common/KEYS' \
- --verify-tar-gz \
- "${WORKSPACE}/hadoop-${HADOOP2_VERSION}-bin.tar.gz" \
- "hadoop/common/hadoop-${HADOOP2_VERSION}/hadoop-${HADOOP2_VERSION}.tar.gz"
- for stale in $(ls -1 "${WORKSPACE}"/hadoop-2*.tar.gz | grep -v ${HADOOP2_VERSION}); do
- echo "Delete stale hadoop 2 cache ${stale}"
- rm -rf $stale
- done
- '''
- stash name: 'hadoop-2', includes: "hadoop-${HADOOP2_VERSION}-bin.tar.gz"
- }
- }
- stage ('hadoop 3 cache') {
- steps {
- script {
- hadoop3_versions = env.HADOOP3_VERSIONS.split(",");
- env.HADOOP3_VERSIONS_REGEX = "[" + hadoop3_versions.join("|") + "]";
- for (hadoop3_version in hadoop3_versions) {
- env.HADOOP3_VERSION = hadoop3_version;
- echo "env.HADOOP3_VERSION" + env.hadoop3_version;
- stage ('Hadoop 3 cache inner stage') {
- // directory must be unique for each parallel stage, because jenkins runs them in the same workspace :(
- dir("downloads-hadoop-${HADOOP3_VERSION}") {
- sh '''#!/usr/bin/env bash
- echo "Make sure we have a directory for downloading dependencies: $(pwd)"
-'''
- } //dir
- sh '''#!/usr/bin/env bash
- set -e
- echo "Ensure we have a copy of Hadoop ${HADOOP3_VERSION}"
- "${WORKSPACE}/component/dev-support/jenkins-scripts/cache-apache-project-artifact.sh" \
- --working-dir "${WORKSPACE}/downloads-hadoop-${HADOOP3_VERSION}" \
- --keys 'https://downloads.apache.org/hadoop/common/KEYS' \
- --verify-tar-gz \
- "${WORKSPACE}/hadoop-${HADOOP3_VERSION}-bin.tar.gz" \
- "hadoop/common/hadoop-${HADOOP3_VERSION}/hadoop-${HADOOP3_VERSION}.tar.gz"
- for stale in $(ls -1 "${WORKSPACE}"/hadoop-3*.tar.gz | grep -v ${HADOOP3_VERSION}); do
- echo "Delete stale hadoop 3 cache ${stale}"
- rm -rf $stale
- done
- '''
- stash name: "hadoop-${HADOOP3_VERSION}", includes: "hadoop-${HADOOP3_VERSION}-bin.tar.gz"
- script {
- if (env.HADOOP3_VERSION == env.HADOOP3_DEFAULT_VERSION) {
- // FIXME: we never unstash this, because we run the packaging tests with the version-specific stashes
- stash(name: "hadoop-3", includes: "hadoop-${HADOOP3_VERSION}-bin.tar.gz")
- } //if
- } //script
- } //stage ('Hadoop 3 cache inner stage')
- } //for
- } //script
- } //steps
- } //stage ('hadoop 3 cache') {
- } //parallel
+ } // stage ('yetus install')
+ } // parallel
} //stage ('thirdparty installs')
stage ('init health results') {
steps {
@@ -208,13 +135,6 @@ pipeline {
stash name: 'jdk8-hadoop3-result', allowEmpty: true, includes: "${OUTPUT_DIR_RELATIVE_JDK8_HADOOP3}/doesn't-match"
stash name: 'jdk11-hadoop3-result', allowEmpty: true, includes: "${OUTPUT_DIR_RELATIVE_JDK11_HADOOP3}/doesn't-match"
stash name: 'jdk17-hadoop3-result', allowEmpty: true, includes: "${OUTPUT_DIR_RELATIVE_JDK17_HADOOP3}/doesn't-match"
- script {
- for (hadoop3_version in hadoop3_versions) {
- // confusing environment vs Groovy variables
- stash(name: "jdk17-hadoop3-backwards-result-${hadoop3_version}", allowEmpty: true, includes: "${env.OUTPUT_DIR_RELATIVE_JDK17_HADOOP3_BACKWARDS}-${hadoop3_version}/doesn't-match")
- }
- }
- stash name: 'srctarball-result', allowEmpty: true, includes: "output-srctarball/doesn't-match"
}
}
stage ('health checks') {
@@ -771,352 +691,6 @@ pipeline {
}
}
}
- // If/when we transition to transient runners, we could run every Hadoop check as a matrix job
- stage ('yetus jdk17 hadoop3 backwards compatibility checks') {
- agent {
- node {
- label 'hbase'
- }
- }
- environment {
- BASEDIR = "${env.WORKSPACE}/component"
- TESTS = "${env.DEEP_CHECKS}"
- SET_JAVA_HOME = "/usr/lib/jvm/java-17"
- // Activates hadoop 3.0 profile in maven runs.
- HADOOP_PROFILE = '3.0'
- // HADOOP_THREE_VERSION is set in script for loop
- TEST_PROFILE = 'runDevTests'
- SKIP_ERRORPRONE = true
- }
- steps {
- script {
- for (hadoop3_version in hadoop3_versions) {
- if (hadoop3_version == env.HADOOP3_DEFAULT_VERSION) {
- // We are running the full test suite, no need to run the dev tests too
- continue
- }
- //HADOOP_THREE_VERSION is the environment variable name expected by the nightly shell script
- env.HADOOP_THREE_VERSION = hadoop3_version;
- env.OUTPUT_DIR_RELATIVE = "${env.OUTPUT_DIR_RELATIVE_JDK17_HADOOP3_BACKWARDS}-${env.HADOOP_THREE_VERSION}"
- env.OUTPUT_DIR = "${env.WORKSPACE}/${env.OUTPUT_DIR_RELATIVE_JDK17_HADOOP3_BACKWARDS}-${env.HADOOP_THREE_VERSION}"
- try {
- stage ('yetus jdk17 hadoop3 backwards compatibility checks inner stage') {
- // Must do prior to anything else, since if one of them timesout we'll stash the commentfile
- sh '''#!/usr/bin/env bash
- set -e
- rm -rf "${OUTPUT_DIR}" && mkdir "${OUTPUT_DIR}"
- rm -f "${OUTPUT_DIR}/commentfile"
- '''
- unstash 'yetus'
- dir('component') {
- checkout scm
- }
- sh '''#!/usr/bin/env bash
- set -e
- rm -rf "${OUTPUT_DIR}/machine" && mkdir "${OUTPUT_DIR}/machine"
- "${BASEDIR}/dev-support/gather_machine_environment.sh" "${OUTPUT_DIR_RELATIVE}/machine"
- echo "got the following saved stats in '${OUTPUT_DIR_RELATIVE}/machine'"
- ls -lh "${OUTPUT_DIR_RELATIVE}/machine"
- '''
- script {
- def ret = sh(
- returnStatus: true,
- script: '''#!/usr/bin/env bash
- set -e
- declare -i status=0
- if "${BASEDIR}/dev-support/hbase_nightly_yetus.sh" ; then
- echo "(/) {color:green}+1 jdk17 hadoop ${HADOOP_THREE_VERSION} backward compatibility checks{color}" > "${OUTPUT_DIR}/commentfile"
- else
- echo "(x) {color:red}-1 jdk17 hadoop ${HADOOP_THREE_VERSION} backward compatibility checks{color}" > "${OUTPUT_DIR}/commentfile"
- status=1
- fi
- echo "-- For more information [see jdk17 report|${BUILD_URL}JDK17_20Nightly_20Build_20Report_20_28Hadoop3_29/]" >> "${OUTPUT_DIR}/commentfile"
- exit "${status}"
- '''
- )
- if (ret != 0) {
- // mark the build as UNSTABLE instead of FAILURE, to avoid skipping the later publish of
- // test output. See HBASE-26339 for more details.
- currentBuild.result = 'UNSTABLE'
- }
- } //script
- } //stage ('yetus jdk17 hadoop3 backwards compatibility checks inner stage') {
- } //try
- finally {
- stash name: "jdk17-hadoop3-backwards-result-${HADOOP_THREE_VERSION}", includes: "${OUTPUT_DIR_RELATIVE}/commentfile"
- junit testResults: "${env.OUTPUT_DIR_RELATIVE}/**/target/**/TEST-*.xml", allowEmptyResults: true
- // zip surefire reports.
- sh '''#!/bin/bash -e
- if [ ! -f "${OUTPUT_DIR}/commentfile" ]; then
- echo "(x) {color:red}-1 jdk17 hadoop ${HADOOP_THREE_VERSION} backward compatibility checks{color}" >"${OUTPUT_DIR}/commentfile"
- echo "-- Something went wrong running this stage, please [check relevant console output|${BUILD_URL}/console]." >> "${OUTPUT_DIR}/commentfile"
- fi
- if [ -d "${OUTPUT_DIR}/archiver" ]; then
- count=$(find "${OUTPUT_DIR}/archiver" -type f | wc -l)
- if [[ 0 -ne ${count} ]]; then
- echo "zipping ${count} archived files"
- zip -q -m -r "${OUTPUT_DIR}/test_logs.zip" "${OUTPUT_DIR}/archiver"
- else
- echo "No archived files, skipping compressing."
- fi
- else
- echo "No archiver directory, skipping compressing."
- fi
- '''
- sshPublisher(publishers: [
- sshPublisherDesc(configName: 'Nightlies',
- transfers: [
- sshTransfer(remoteDirectory: "hbase/${JOB_NAME}/${BUILD_NUMBER}",
- sourceFiles: "${env.OUTPUT_DIR_RELATIVE}/test_logs.zip"
- )
- ]
- )
- ])
- // remove the big test logs zip file, store the nightlies url in test_logs.html
- sh '''#!/bin/bash -e
- if [ -f "${OUTPUT_DIR}/test_logs.zip" ]; then
- echo "Remove ${OUTPUT_DIR}/test_logs.zip for saving space"
- rm -rf "${OUTPUT_DIR}/test_logs.zip"
- python3 ${BASEDIR}/dev-support/gen_redirect_html.py "${ASF_NIGHTLIES_BASE}/${OUTPUT_DIR_RELATIVE}" > "${OUTPUT_DIR}/test_logs.html"
- else
- echo "No test_logs.zip, skipping"
- fi
- '''
- // Has to be relative to WORKSPACE.
- archiveArtifacts artifacts: "${env.OUTPUT_DIR_RELATIVE}/*"
- archiveArtifacts artifacts: "${env.OUTPUT_DIR_RELATIVE}/**/*"
- publishHTML target: [
- allowMissing : true,
- keepAll : true,
- alwaysLinkToLastBuild: true,
- // Has to be relative to WORKSPACE.
- reportDir : "${env.OUTPUT_DIR_RELATIVE}",
- reportFiles : 'console-report.html',
- reportName : "JDK17 Nightly Build Report (Hadoop ${HADOOP_THREE_VERSION} backwards compatibility)"
- ]
- } //finally
- } // for
- } //script
- } //steps
- } //stage ('yetus jdk17 hadoop3 backwards compatibility checks')
-
- // This is meant to mimic what a release manager will do to create RCs.
- // See http://hbase.apache.org/book.html#maven.release
- // TODO (HBASE-23870): replace this with invocation of the release tool
- stage ('packaging and integration') {
- agent {
- node {
- label 'hbase'
- }
- }
- environment {
- BASEDIR = "${env.WORKSPACE}/component"
- BRANCH = "${env.BRANCH_NAME}"
- }
- steps {
- dir('component') {
- checkout scm
- }
- sh '''#!/bin/bash -e
- echo "Setting up directories"
- rm -rf "output-srctarball" && mkdir "output-srctarball"
- rm -rf "output-integration" && mkdir "output-integration" "output-integration/hadoop-2" "output-integration/hadoop-3" "output-integration/hadoop-3-shaded"
- rm -rf "unpacked_src_tarball" && mkdir "unpacked_src_tarball"
- rm -rf "hbase-install" && mkdir "hbase-install"
- rm -rf "hbase-client" && mkdir "hbase-client"
- rm -rf "hbase-hadoop3-install"
- rm -rf "hbase-hadoop3-client"
- rm -rf "hadoop-2" && mkdir "hadoop-2"
- rm -rf "hadoop-3" && mkdir "hadoop-3"
- rm -rf ".m2-for-repo" && mkdir ".m2-for-repo"
- rm -rf ".m2-for-src" && mkdir ".m2-for-src"
- # remove old hadoop tarballs in workspace
- rm -rf hadoop-2*.tar.gz
- rm -rf hadoop-3*.tar.gz
- rm -f "output-integration/commentfile"
- '''
- sh '''#!/usr/bin/env bash
- set -e
- rm -rf "output-srctarball/machine" && mkdir "output-srctarball/machine"
- "${BASEDIR}/dev-support/gather_machine_environment.sh" "output-srctarball/machine"
- echo "got the following saved stats in 'output-srctarball/machine'"
- ls -lh "output-srctarball/machine"
- '''
- sh '''#!/bin/bash -e
- echo "Checking the steps for an RM to make a source artifact, then a binary artifact."
- docker build -t hbase-integration-test -f "${BASEDIR}/dev-support/docker/Dockerfile" .
- docker run --rm -v "${WORKSPACE}":/hbase -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \
- -u `id -u`:`id -g` -e JAVA_HOME="/usr/lib/jvm/java-17" --workdir=/hbase hbase-integration-test \
- "component/dev-support/hbase_nightly_source-artifact.sh" \
- --intermediate-file-dir output-srctarball \
- --unpack-temp-dir unpacked_src_tarball \
- --maven-m2-initial .m2-for-repo \
- --maven-m2-src-build .m2-for-src \
- --clean-source-checkout \
- component
- if [ $? -eq 0 ]; then
- echo '(/) {color:green}+1 source release artifact{color}\n-- See build output for details.' >output-srctarball/commentfile
- else
- echo '(x) {color:red}-1 source release artifact{color}\n-- See build output for details.' >output-srctarball/commentfile
- exit 1
- fi
- '''
- echo "unpacking the hbase bin tarball into 'hbase-install' and the client tarball into 'hbase-client'"
- sh '''#!/bin/bash -e
- if [ 2 -ne $(ls -1 "${WORKSPACE}"/unpacked_src_tarball/hbase-assembly/target/hbase-*-bin.tar.gz | grep -v hadoop3 | wc -l) ]; then
- echo '(x) {color:red}-1 testing binary artifact{color}\n-- source tarball did not produce the expected binaries.' >>output-srctarball/commentfile
- exit 1
- fi
- install_artifact=$(ls -1 "${WORKSPACE}"/unpacked_src_tarball/hbase-assembly/target/hbase-*-bin.tar.gz | grep -v client-bin | grep -v hadoop3)
- tar --strip-component=1 -xzf "${install_artifact}" -C "hbase-install"
- client_artifact=$(ls -1 "${WORKSPACE}"/unpacked_src_tarball/hbase-assembly/target/hbase-*-client-bin.tar.gz | grep -v hadoop3)
- tar --strip-component=1 -xzf "${client_artifact}" -C "hbase-client"
- if [ 2 -eq $(ls -1 "${WORKSPACE}"/unpacked_src_tarball/hbase-assembly/target/hbase-*-hadoop3-*-bin.tar.gz | wc -l) ]; then
- echo "hadoop3 artifacts available, unpacking the hbase hadoop3 bin tarball into 'hbase-hadoop3-install' and the client hadoop3 tarball into 'hbase-hadoop3-client'"
- mkdir hbase-hadoop3-install
- mkdir hbase-hadoop3-client
- hadoop3_install_artifact=$(ls -1 "${WORKSPACE}"/unpacked_src_tarball/hbase-assembly/target/hbase-*-hadoop3-*-bin.tar.gz | grep -v client-bin)
- tar --strip-component=1 -xzf "${hadoop3_install_artifact}" -C "hbase-hadoop3-install"
- hadoop3_client_artifact=$(ls -1 "${WORKSPACE}"/unpacked_src_tarball/hbase-assembly/target/hbase-*-hadoop3-*-client-bin.tar.gz)
- tar --strip-component=1 -xzf "${hadoop3_client_artifact}" -C "hbase-hadoop3-client"
- fi
- '''
- unstash 'hadoop-2'
- sh '''#!/bin/bash -xe
- if [[ "${BRANCH}" == *"branch-2"* ]]; then
- echo "Attempting to use run an instance on top of Hadoop 2."
- artifact=$(ls -1 "${WORKSPACE}"/hadoop-2*.tar.gz | head -n 1)
- tar --strip-components=1 -xzf "${artifact}" -C "hadoop-2"
- docker build -t hbase-integration-test -f "${BASEDIR}/dev-support/docker/Dockerfile" .
- docker run --rm -v "${WORKSPACE}":/hbase -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \
- -u `id -u`:`id -g` -e JAVA_HOME="/usr/lib/jvm/java-8" --workdir=/hbase hbase-integration-test \
- component/dev-support/hbase_nightly_pseudo-distributed-test.sh \
- --single-process \
- --working-dir output-integration/hadoop-2 \
- --hbase-client-install "hbase-client" \
- hbase-install \
- hadoop-2/bin/hadoop \
- hadoop-2/share/hadoop/yarn/timelineservice \
- hadoop-2/share/hadoop/yarn/test/hadoop-yarn-server-tests-*-tests.jar \
- hadoop-2/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-*-tests.jar \
- hadoop-2/bin/mapred \
- >output-integration/hadoop-2.log 2>&1
- if [ $? -ne 0 ]; then
- echo "(x) {color:red}-1 client integration test{color}\n--Failed when running client tests on top of Hadoop 2. [see log for details|${BUILD_URL}/artifact/output-integration/hadoop-2.log]. (note that this means we didn't run on Hadoop 3)" >output-integration/commentfile
- exit 2
- fi
- echo "(/) {color:green}+1 client integration test for HBase 2 {color}" >output-integration/commentfile
- else
- echo "Skipping to run against Hadoop 2 for branch ${BRANCH}"
- fi
- '''
- script {
- for (hadoop3_version in hadoop3_versions) {
- env.HADOOP3_VERSION = hadoop3_version;
- echo "env.HADOOP3_VERSION" + env.hadoop3_version;
- stage ("packaging and integration Hadoop 3 inner stage ") {
- unstash "hadoop-" + env.HADOOP3_VERSION
- sh '''#!/bin/bash -e
- echo "Attempting to use run an instance on top of Hadoop ${HADOOP3_VERSION}."
- # Clean up any previous tested Hadoop3 files before unpacking the current one
- rm -rf hadoop-3/*
- # Create working dir
- rm -rf "output-integration/hadoop-${HADOOP3_VERSION}" && mkdir "output-integration/hadoop-${HADOOP3_VERSION}"
- rm -rf "output-integration/hadoop-${HADOOP3_VERSION}-shaded" && mkdir "output-integration/hadoop-${HADOOP3_VERSION}-shaded"
- artifact=$(ls -1 "${WORKSPACE}"/hadoop-${HADOOP3_VERSION}-bin.tar.gz | head -n 1)
- tar --strip-components=1 -xzf "${artifact}" -C "hadoop-3"
- # we need to patch some files otherwise minicluster will fail to start, see MAPREDUCE-7471
- ${BASEDIR}/dev-support/patch-hadoop3.sh hadoop-3
- hbase_install_dir="hbase-install"
- hbase_client_dir="hbase-client"
- if [ -d "hbase-hadoop3-install" ]; then
- echo "run hadoop3 client integration test against hbase hadoop3 binaries"
- hbase_install_dir="hbase-hadoop3-install"
- hbase_client_dir="hbase-hadoop3-client"
- fi
- docker build -t hbase-integration-test -f "${BASEDIR}/dev-support/docker/Dockerfile" .
- docker run --rm -v "${WORKSPACE}":/hbase -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \
- -u `id -u`:`id -g` -e JAVA_HOME="/usr/lib/jvm/java-17" \
- -e HADOOP_OPTS="--add-opens java.base/java.lang=ALL-UNNAMED" \
- --workdir=/hbase hbase-integration-test \
- component/dev-support/hbase_nightly_pseudo-distributed-test.sh \
- --single-process \
- --working-dir output-integration/hadoop-${HADOOP3_VERSION} \
- --hbase-client-install ${hbase_client_dir} \
- ${hbase_install_dir} \
- hadoop-3/bin/hadoop \
- hadoop-3/share/hadoop/yarn/timelineservice \
- hadoop-3/share/hadoop/yarn/test/hadoop-yarn-server-tests-*-tests.jar \
- hadoop-3/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-*-tests.jar \
- hadoop-3/bin/mapred \
- >output-integration/hadoop-${HADOOP3_VERSION}.log 2>&1
- if [ $? -ne 0 ]; then
- echo "(x) {color:red}-1 client integration test{color}\n--Failed when running client tests on top of Hadoop ${HADOOP3_VERSION}. [see log for details|${BUILD_URL}/artifact/output-integration/hadoop-${HADOOP3_VERSION}.log]. (note that this means we didn't check the Hadoop ${HADOOP3_VERSION} shaded client)" >> output-integration/commentfile
- exit 2
- fi
- echo "Attempting to use run an instance on top of Hadoop ${HADOOP3_VERSION}, relying on the Hadoop client artifacts for the example client program."
- docker run --rm -v "${WORKSPACE}":/hbase -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \
- -u `id -u`:`id -g` -e JAVA_HOME="/usr/lib/jvm/java-17" \
- -e HADOOP_OPTS="--add-opens java.base/java.lang=ALL-UNNAMED" \
- --workdir=/hbase hbase-integration-test \
- component/dev-support/hbase_nightly_pseudo-distributed-test.sh \
- --single-process \
- --hadoop-client-classpath hadoop-3/share/hadoop/client/hadoop-client-api-*.jar:hadoop-3/share/hadoop/client/hadoop-client-runtime-*.jar \
- --working-dir output-integration/hadoop-${HADOOP3_VERSION}-shaded \
- --hbase-client-install ${hbase_client_dir} \
- ${hbase_install_dir} \
- hadoop-3/bin/hadoop \
- hadoop-3/share/hadoop/yarn/timelineservice \
- hadoop-3/share/hadoop/yarn/test/hadoop-yarn-server-tests-*-tests.jar \
- hadoop-3/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-*-tests.jar \
- hadoop-3/bin/mapred \
- >output-integration/hadoop-${HADOOP3_VERSION}-shaded.log 2>&1
- if [ $? -ne 0 ]; then
- echo "(x) {color:red}-1 client integration test{color}\n--Failed when running client tests on top of Hadoop ${HADOOP3_VERSION} using Hadoop's shaded client. [see log for details|${BUILD_URL}/artifact/output-integration/hadoop-${HADOOP3_VERSION}-shaded.log]." >> output-integration/commentfile
- exit 2
- fi
- echo "(/) {color:green}+1 client integration test for ${HADOOP3_VERSION} {color}" >> output-integration/commentfile
- '''
- } //stage ("packaging and integration Hadoop 3 inner stage ")
- } //for
- } // script
- } //steps
- post {
- always {
- sh '''#!/bin/bash -e
- if [ ! -f "output-integration/commentfile" ]; then
- echo "(x) {color:red}-1 source release artifact{color}\n-- Something went wrong with this stage, [check relevant console output|${BUILD_URL}/console]." >output-srctarball/commentfile
- echo "(x) {color:red}-1 client integration test{color}\n-- Something went wrong with this stage, [check relevant console output|${BUILD_URL}/console]." >output-integration/commentfile
- fi
- '''
- stash name: 'srctarball-result', includes: "output-srctarball/commentfile,output-integration/commentfile"
- sshPublisher(publishers: [
- sshPublisherDesc(configName: 'Nightlies',
- transfers: [
- sshTransfer(remoteDirectory: "hbase/${JOB_NAME}/${BUILD_NUMBER}",
- sourceFiles: "output-srctarball/hbase-src.tar.gz"
- )
- ]
- )
- ])
- // remove the big src tarball, store the nightlies url in hbase-src.html
- sh '''#!/bin/bash -e
- SRC_TAR="${WORKSPACE}/output-srctarball/hbase-src.tar.gz"
- if [ -f "${SRC_TAR}" ]; then
- echo "Remove ${SRC_TAR} for saving space"
- rm -rf "${SRC_TAR}"
- python3 ${BASEDIR}/dev-support/gen_redirect_html.py "${ASF_NIGHTLIES_BASE}/output-srctarball" > "${WORKSPACE}/output-srctarball/hbase-src.html"
- else
- echo "No hbase-src.tar.gz, skipping"
- fi
- '''
- archiveArtifacts artifacts: 'output-srctarball/*'
- archiveArtifacts artifacts: 'output-srctarball/**/*'
- archiveArtifacts artifacts: 'output-integration/*'
- archiveArtifacts artifacts: 'output-integration/**/*'
- } //always
- } //post
- } //stage packaging
} // parallel
} //stage:_health checks
} //stages
@@ -1133,32 +707,18 @@ pipeline {
rm -rf ${OUTPUT_DIR_RELATIVE_JDK8_HADOOP3}
rm -rf ${OUTPUT_DIR_RELATIVE_JDK11_HADOOP3}
rm -rf ${OUTPUT_DIR_RELATIVE_JDK17_HADOOP3}
- rm -rf ${OUTPUT_DIR_RELATIVE_JDK17_HADOOP3_BACKWARDS}-*
- rm -rf output-srctarball
- rm -rf output-integration
'''
unstash 'general-result'
unstash 'jdk8-hadoop2-result'
unstash 'jdk8-hadoop3-result'
unstash 'jdk11-hadoop3-result'
unstash 'jdk17-hadoop3-result'
- unstash 'srctarball-result'
def results = ["${env.OUTPUT_DIR_RELATIVE_GENERAL}/commentfile",
"${env.OUTPUT_DIR_RELATIVE_JDK8_HADOOP2}/commentfile",
"${env.OUTPUT_DIR_RELATIVE_JDK8_HADOOP3}/commentfile",
"${env.OUTPUT_DIR_RELATIVE_JDK11_HADOOP3}/commentfile",
"${env.OUTPUT_DIR_RELATIVE_JDK17_HADOOP3}/commentfile"]
- for (hadoop3_version in hadoop3_versions) {
- if (hadoop3_version == env.HADOOP3_DEFAULT_VERSION) {
- // We haven't run these tests
- continue
- }
- unstash("jdk17-hadoop3-backwards-result-${hadoop3_version}")
- results.add("${env.OUTPUT_DIR_RELATIVE_JDK17_HADOOP3_BACKWARDS}-${hadoop3_version}/commentfile")
- }
- results.add('output-srctarball/commentfile')
- results.add('output-integration/commentfile')
echo env.BRANCH_NAME
echo env.BUILD_URL
echo currentBuild.result
diff --git a/dev-support/blanks-eol-ignore.txt b/dev-support/blanks-eol-ignore.txt
index 6912be308371..51edc75be9d6 100644
--- a/dev-support/blanks-eol-ignore.txt
+++ b/dev-support/blanks-eol-ignore.txt
@@ -20,5 +20,5 @@
.*/gen-cpp/.*
.*/gen-perl/.*
.*/gen-php/.*
-.*/gen-py/.*
+.*/gen_py/.*
.*/gen-rb/.*
diff --git a/dev-support/blanks-tabs-ignore.txt b/dev-support/blanks-tabs-ignore.txt
index 49185487846e..54f35708c4d8 100644
--- a/dev-support/blanks-tabs-ignore.txt
+++ b/dev-support/blanks-tabs-ignore.txt
@@ -20,7 +20,7 @@
.*/gen-cpp/.*
.*/gen-perl/.*
.*/gen-php/.*
-.*/gen-py/.*
+.*/gen_py/.*
.*/gen-rb/.*
# we have tabs in asciidoc, not sure whether it is OK to replace them with spaces
src/main/asciidoc/.*
diff --git a/dev-support/flaky-tests/report-flakies.py b/dev-support/flaky-tests/report-flakies.py
index 16096e3344a5..33e9a12f0d5e 100755
--- a/dev-support/flaky-tests/report-flakies.py
+++ b/dev-support/flaky-tests/report-flakies.py
@@ -54,6 +54,11 @@
parser.add_argument('--is-yetus', metavar='True/False', action='append', choices=['True', 'False'],
help='True, if build is yetus style i.e. look for maven output in artifacts; '
'False, if maven output is in /consoleText itself.')
+parser.add_argument('--excludes-threshold-flakiness', metavar='n', type=float, default=20.0,
+ required=False, help='Flakiness threshold for adding a test to excludes file')
+parser.add_argument('--excludes-threshold-runs', metavar='n', type=int, default=10,
+ required=False,
+ help='The times of a test should run before it can be added to excludes file')
parser.add_argument(
"--mvn", action="store_true",
help="Writes two strings for including/excluding these flaky tests using maven flags. These "
@@ -149,7 +154,6 @@ def expand_multi_config_projects(cli_args):
'excludes': excluded_builds, 'is_yetus': is_yetus})
return final_expanded_urls
-
# Set of timeout/failed tests across all given urls.
all_timeout_tests = set()
all_failed_tests = set()
@@ -160,6 +164,8 @@ def expand_multi_config_projects(cli_args):
# Contains { : [run_ids] }
# Used for common min/max build ids when generating sparklines.
url_to_build_ids = OrderedDict()
+all_flaky_results = {}
+
# Iterates over each url, gets test results and prints flaky tests.
expanded_urls = expand_multi_config_projects(args)
@@ -205,36 +211,46 @@ def expand_multi_config_projects(cli_args):
bad_tests.update(failed_tests.union(hanging_tests))
# For each bad test, get build ids where it ran, timed out, failed or hanged.
- test_to_build_ids = {key : {'all' : set(), 'timeout': set(), 'failed': set(),
- 'hanging' : set(), 'bad_count' : 0}
+ test_to_build_ids = {key: {'all': set(), 'timeout': set(), 'failed': set(),
+ 'hanging': set(), 'bad_count': 0}
for key in bad_tests}
+
for build in build_id_to_results:
[all_tests, failed_tests, timeout_tests, hanging_tests] = build_id_to_results[build]
- for bad_test in test_to_build_ids:
+ for bad_test, test_result in test_to_build_ids.items():
is_bad = False
if all_tests.issuperset([bad_test]):
- test_to_build_ids[bad_test]["all"].add(build)
+ test_result["all"].add(build)
if timeout_tests.issuperset([bad_test]):
- test_to_build_ids[bad_test]['timeout'].add(build)
+ test_result['timeout'].add(build)
is_bad = True
if failed_tests.issuperset([bad_test]):
- test_to_build_ids[bad_test]['failed'].add(build)
+ test_result['failed'].add(build)
is_bad = True
if hanging_tests.issuperset([bad_test]):
- test_to_build_ids[bad_test]['hanging'].add(build)
+ test_result['hanging'].add(build)
is_bad = True
if is_bad:
- test_to_build_ids[bad_test]['bad_count'] += 1
+ test_result['bad_count'] += 1
# Calculate flakyness % and successful builds for each test. Also sort build ids.
- for bad_test in test_to_build_ids:
- test_result = test_to_build_ids[bad_test]
+ for bad_test, test_result in test_to_build_ids.items():
test_result['flakyness'] = test_result['bad_count'] * 100.0 / len(test_result['all'])
test_result['success'] = (test_result['all'].difference(
test_result['failed'].union(test_result['hanging'])))
for key in ['all', 'timeout', 'failed', 'hanging', 'success']:
test_result[key] = sorted(test_result[key])
-
+ # record flaky test result
+ # record the one with more runs, or greater flakiness if runs are equal
+ if bad_test not in all_flaky_results:
+ all_flaky_results[bad_test] = {'runs': len(test_result['all']),
+ 'flakyness': test_result['flakyness']}
+ elif all_flaky_results[bad_test]['runs'] < len(test_result['all']):
+ all_flaky_results[bad_test] = {'runs': len(test_result['all']),
+ 'flakyness': test_result['flakyness']}
+ elif all_flaky_results[bad_test]['runs'] == len(test_result['all']) and \
+ all_flaky_results[bad_test]['flakyness'] < test_result['flakyness']:
+ all_flaky_results[bad_test]['flakyness'] = test_result['flakyness']
# Sort tests in descending order by flakyness.
sorted_test_to_build_ids = OrderedDict(
@@ -260,14 +276,21 @@ def expand_multi_config_projects(cli_args):
print("Builds without any test runs: {}".format(build_ids_without_tests_run))
print("")
-
all_bad_tests = all_hanging_tests.union(all_failed_tests)
if args.mvn:
includes = ",".join(all_bad_tests)
with open(output_dir + "/includes", "w") as inc_file:
inc_file.write(includes)
- excludes = ["**/{0}.java".format(bad_test) for bad_test in all_bad_tests]
+ excludes = []
+ for bad_test in all_bad_tests:
+ if bad_test not in all_flaky_results:
+ print(f"No flaky record found for {bad_test}")
+ continue
+ test_result = all_flaky_results[bad_test]
+ if test_result['flakyness'] > args.excludes_threshold_flakiness and \
+ test_result['runs'] >= args.excludes_threshold_runs:
+ excludes.append(f"**/{bad_test}.java")
with open(output_dir + "/excludes", "w") as exc_file:
exc_file.write(",".join(excludes))
@@ -283,5 +306,5 @@ def expand_multi_config_projects(cli_args):
with open(output_dir + "/dashboard.html", "w") as f:
datetime = time.strftime("%m/%d/%Y %H:%M:%S")
- f.write(template.render(datetime=datetime, bad_tests_count=len(all_bad_tests),
+ f.write(template.render(datetime=datetime, bad_tests_count=len(bad_tests),
results=url_to_bad_test_results, build_ids=url_to_build_ids))
diff --git a/dev-support/gh_hide_old_comments.sh b/dev-support/gh_hide_old_comments.sh
index 61217cfa241b..abba55a39ad2 100755
--- a/dev-support/gh_hide_old_comments.sh
+++ b/dev-support/gh_hide_old_comments.sh
@@ -40,25 +40,79 @@ declare CURL="${CURL:-curl}"
function fetch_comments {
local pr="$1"
local comments_file
+ local page_file
+ local headers_file
local -a curl_args
- curl_args=(
- --fail
- "${GITHUB_AUTH[@]}"
- --header 'Accept: application/vnd.github+json'
- --header 'X-GitHub-Api-Version: 2022-11-28'
- --request GET
- --url "${GITHUB_API_URL}/repos/${REPO}/issues/${pr}/comments?per_page=500"
- )
- if [ "${DEBUG}" = true ] ; then
- curl_args+=(--verbose)
- else
- curl_args+=(--silent)
- fi
+ local page=1
+ local next_url
comments_file="$(mktemp "comments_${pr}" 2>/dev/null || mktemp -t "comments_${pr}.XXXXXXXXXX")" || \
{ >&2 echo 'cannot create temp file'; exit 1 ;}
- "${CURL}" "${curl_args[@]}" > "${comments_file}"
+ page_file="$(mktemp "page_${pr}" 2>/dev/null || mktemp -t "page_${pr}.XXXXXXXXXX")" || \
+ { >&2 echo 'cannot create temp file'; exit 1 ;}
+ headers_file="$(mktemp "headers_${pr}" 2>/dev/null || mktemp -t "headers_${pr}.XXXXXXXXXX")" || \
+ { >&2 echo 'cannot create temp file'; exit 1 ;}
+
+ # cleanup temp files on error
+ trap 'rm -f "${page_file}" "${headers_file}"; exit 1' ERR
+
+ next_url="${GITHUB_API_URL}/repos/${REPO}/issues/${pr}/comments?per_page=100"
+
+ # start with empty JSON array
+ echo '[]' > "${comments_file}"
+
+ while [ -n "${next_url}" ] ; do
+ curl_args=(
+ --fail
+ --max-time 30
+ "${GITHUB_AUTH[@]}"
+ --header 'Accept: application/vnd.github+json'
+ --header 'X-GitHub-Api-Version: 2022-11-28'
+ --dump-header "${headers_file}"
+ --request GET
+ --url "${next_url}"
+ )
+ if [ "${DEBUG}" = true ] ; then
+ curl_args+=(--verbose)
+ >&2 echo "Fetching page ${page}: ${next_url}"
+ else
+ curl_args+=(--silent)
+ fi
+
+ if ! "${CURL}" "${curl_args[@]}" > "${page_file}"; then
+ >&2 echo "Failed to fetch page ${page}: ${next_url}"
+ rm -f "${page_file}" "${headers_file}"
+ exit 1
+ fi
+
+ if [ "${DEBUG}" = 'true' ] ; then
+ >&2 echo "Page ${page} returned $(jq length "${page_file}") comments"
+ fi
+
+ # merge this page into the accumulated results
+ if ! jq -s '.[0] + .[1]' "${comments_file}" "${page_file}" > "${comments_file}.tmp"; then
+ >&2 echo "Failed to merge comments from page ${page}"
+ rm -f "${page_file}" "${headers_file}" "${comments_file}.tmp"
+ exit 1
+ fi
+ mv "${comments_file}.tmp" "${comments_file}"
+
+ # check for next page in Link header
+ # Link header format: ; rel="next", ; rel="last"
+ # Extract URL associated with rel="next" regardless of position
+ next_url=""
+ if grep -qi '^link:' "${headers_file}" ; then
+ next_url=$(grep -i '^link:' "${headers_file}" | tr ',' '\n' | grep 'rel="next"' | sed -n 's/.*<\([^>]*\)>.*/\1/p' || true)
+ fi
+
+ page=$((page + 1))
+ done
+
+ rm -f "${page_file}" "${headers_file}"
+ trap - ERR
+
if [ "${DEBUG}" = 'true' ] ; then
+ >&2 echo "Total comments fetched: $(jq length "${comments_file}")"
>&2 cat "${comments_file}"
fi
echo "${comments_file}"
@@ -104,11 +158,16 @@ function identify_most_recent_build_number {
local pr="$1"
local comments_file="$2"
local jq_filter
+ local url_pattern="${JOB_NAME}/job/PR-${pr}/(?[0-9]+)/"
+ # GitHub Actions URLs don't have /job/ in them
+ if [[ "${JOB_NAME}" == *"GH-Actions"* ]]; then
+ url_pattern="${JOB_NAME}/PR-${pr}/(?[0-9]+)/"
+ fi
read -r -d '' jq_filter << EOF || :
.[] \
| select(.user.id == ${BUILD_BOT_USER_ID}) \
| .body \
-| capture("${JOB_NAME}/job/PR-${pr}/(?[0-9]+)/") \
+| capture("${url_pattern}") \
| .buildnum
EOF
@@ -122,10 +181,15 @@ function identify_old_comment_ids {
local comments_file="$2"
local most_recent_build_number="$3"
local jq_filter
+ local url_pattern="${JOB_NAME}/job/PR-${pr}/(?[0-9]+)/"
+ # GitHub Actions URLs don't have /job/ in them
+ if [[ "${JOB_NAME}" == *"GH-Actions"* ]]; then
+ url_pattern="${JOB_NAME}/PR-${pr}/(?[0-9]+)/"
+ fi
read -r -d '' jq_filter << EOF || :
.[] \
| select(.user.id == ${BUILD_BOT_USER_ID}) \
-| { node_id, buildnum: (.body | capture("${JOB_NAME}/job/PR-${pr}/(?[0-9]+)/") | .buildnum | tonumber) } \
+| { node_id, buildnum: (.body | capture("${url_pattern}") | .buildnum | tonumber) } \
| select(.buildnum < (${most_recent_build_number} | tonumber)) \
| .node_id
EOF
diff --git a/dev-support/hadoop3-backwards-compatibility-check.Jenkinsfile b/dev-support/hadoop3-backwards-compatibility-check.Jenkinsfile
new file mode 100644
index 000000000000..8e8eff8ded30
--- /dev/null
+++ b/dev-support/hadoop3-backwards-compatibility-check.Jenkinsfile
@@ -0,0 +1,326 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// Jenkinsfile for Hadoop3 Backwards Compatibility Checks
+// Uses matrix job to parallelize checks across different Hadoop3 versions
+
+pipeline {
+ agent {
+ node {
+ label 'hbase'
+ }
+ }
+ triggers {
+ pollSCM('H H */2 * *')
+ }
+ options {
+ buildDiscarder(logRotator(numToKeepStr: '20'))
+ timeout (time: 8, unit: 'HOURS')
+ timestamps()
+ skipDefaultCheckout()
+ disableConcurrentBuilds()
+ }
+ environment {
+ YETUS_RELEASE = '0.15.0'
+ HADOOP_VERSIONS = "3.2.4,3.3.5,3.3.6,3.4.0,3.4.1,3.4.2"
+ }
+ parameters {
+ booleanParam(name: 'USE_YETUS_PRERELEASE', defaultValue: false, description: '''Check to use the current HEAD of apache/yetus rather than our configured release.
+
+ Should only be used manually when e.g. there is some non-work-aroundable issue in yetus we are checking a fix for.''')
+ booleanParam(name: 'DEBUG', defaultValue: false, description: 'Produce a lot more meta-information.')
+ }
+ stages {
+ stage ('scm-checkout') {
+ steps {
+ dir('component') {
+ checkout scm
+ }
+ }
+ }
+ stage ('thirdparty installs') {
+ parallel {
+ stage ('yetus install') {
+ steps {
+ dir('downloads-yetus') {
+ sh '''#!/usr/bin/env bash
+ echo "Make sure we have a directory for downloading dependencies: $(pwd)"
+ '''
+ }
+ sh '''#!/usr/bin/env bash
+ set -e
+ echo "Ensure we have a copy of Apache Yetus."
+ if [[ true != "${USE_YETUS_PRERELEASE}" ]]; then
+ YETUS_DIR="${WORKSPACE}/yetus-${YETUS_RELEASE}"
+ echo "Checking for Yetus ${YETUS_RELEASE} in '${YETUS_DIR}'"
+ if ! "${YETUS_DIR}/bin/test-patch" --version >/dev/null 2>&1 ; then
+ rm -rf "${YETUS_DIR}"
+ "${WORKSPACE}/component/dev-support/jenkins-scripts/cache-apache-project-artifact.sh" \
+ --working-dir "${WORKSPACE}/downloads-yetus" \
+ --keys 'https://downloads.apache.org/yetus/KEYS' \
+ --verify-tar-gz \
+ "${WORKSPACE}/yetus-${YETUS_RELEASE}-bin.tar.gz" \
+ "yetus/${YETUS_RELEASE}/apache-yetus-${YETUS_RELEASE}-bin.tar.gz"
+ mv "yetus-${YETUS_RELEASE}-bin.tar.gz" yetus.tar.gz
+ else
+ echo "Reusing cached install of Apache Yetus version ${YETUS_RELEASE}."
+ fi
+ else
+ YETUS_DIR="${WORKSPACE}/yetus-git"
+ rm -rf "${YETUS_DIR}"
+ echo "downloading from github"
+ curl -L --fail https://api.github.com/repos/apache/yetus/tarball/HEAD -o yetus.tar.gz
+ fi
+ if [ ! -d "${YETUS_DIR}" ]; then
+ echo "unpacking yetus into '${YETUS_DIR}'"
+ mkdir -p "${YETUS_DIR}"
+ gunzip -c yetus.tar.gz | tar xpf - -C "${YETUS_DIR}" --strip-components 1
+ fi
+ '''
+ stash name: 'yetus', includes: "yetus-*/*,yetus-*/**/*"
+ }
+ }
+ }
+ }
+ stage ('backwards compatibility checks') {
+ matrix {
+ axes {
+ axis {
+ name 'HADOOP3_VERSION'
+ values '3.2.4', '3.3.5', '3.3.6', '3.4.0', '3.4.1', '3.4.2'
+ }
+ }
+ agent {
+ node {
+ label 'hbase'
+ }
+ }
+ when {
+ expression {
+ if (HADOOP3_VERSION == '3.2.4') {
+ // only branch-2.5 need to run against hadoop 3.2.4, here we also includes
+ // HBASE-XXXXX-branch-2.5 feature branch
+ return env.BRANCH_NAME.contains('branch-2.5')
+ }
+ return true
+ }
+ }
+ environment {
+ PROJECT = 'hbase'
+ BASEDIR = "${WORKSPACE}/component"
+ PERSONALITY_FILE = "${BASEDIR}/dev-support/hbase-personality.sh"
+ TESTS_FILTER = 'checkstyle,javac,javadoc,pylint,shellcheck,shelldocs,blanks,perlcritic,ruby-lint,rubocop'
+ EXCLUDE_TESTS_URL = "${JENKINS_URL}/job/HBase-Find-Flaky-Tests/job/${BRANCH_NAME}/lastSuccessfulBuild/artifact/output/excludes"
+ ASF_NIGHTLIES = 'https://nightlies.apache.org'
+ ASF_NIGHTLIES_BASE_ORI = "${ASF_NIGHTLIES}/hbase/${JOB_NAME}/${BUILD_NUMBER}"
+ ASF_NIGHTLIES_BASE = "${ASF_NIGHTLIES_BASE_ORI.replaceAll(' ', '%20')}"
+ TESTS = 'compile,htmlout,javac,maven,mvninstall,shadedjars,unit'
+ SET_JAVA_HOME = "/usr/lib/jvm/java-17"
+ HADOOP_PROFILE = '3.0'
+ TEST_PROFILE = 'runDevTests'
+ SKIP_ERRORPRONE = true
+ OUTPUT_DIR_RELATIVE = "output-jdk17-hadoop3-backwards-${HADOOP3_VERSION}"
+ OUTPUT_DIR = "${WORKSPACE}/${OUTPUT_DIR_RELATIVE}"
+ AUTHOR_IGNORE_LIST = 'src/main/asciidoc/_chapters/developer.adoc'
+ BLANKS_EOL_IGNORE_FILE = 'dev-support/blanks-eol-ignore.txt'
+ BLANKS_TABS_IGNORE_FILE = 'dev-support/blanks-tabs-ignore.txt'
+ // output from surefire; sadly the archive function in yetus only works on file names.
+ ARCHIVE_PATTERN_LIST = 'TEST-*.xml,org.apache.h*.txt,*.dumpstream,*.dump'
+ }
+ stages {
+ stage ('run checks') {
+ steps {
+ sh '''#!/usr/bin/env bash
+ set -e
+ rm -rf "${OUTPUT_DIR}" && mkdir "${OUTPUT_DIR}"
+ rm -f "${OUTPUT_DIR}/commentfile"
+ '''
+ unstash 'yetus'
+ dir('component') {
+ checkout scm
+ }
+ sh '''#!/usr/bin/env bash
+ set -e
+ rm -rf "${OUTPUT_DIR}/machine" && mkdir "${OUTPUT_DIR}/machine"
+ "${BASEDIR}/dev-support/gather_machine_environment.sh" "${OUTPUT_DIR_RELATIVE}/machine"
+ echo "got the following saved stats in '${OUTPUT_DIR_RELATIVE}/machine'"
+ ls -lh "${OUTPUT_DIR_RELATIVE}/machine"
+ '''
+ script {
+ def ret = sh(
+ returnStatus: true,
+ script: '''#!/usr/bin/env bash
+ set -e
+ declare -i status=0
+ if "${BASEDIR}/dev-support/hbase_nightly_yetus.sh" ; then
+ echo "(/) {color:green}+1 jdk17 hadoop ${HADOOP3_VERSION} backward compatibility checks{color}" > "${OUTPUT_DIR}/commentfile"
+ else
+ echo "(x) {color:red}-1 jdk17 hadoop ${HADOOP3_VERSION} backward compatibility checks{color}" > "${OUTPUT_DIR}/commentfile"
+ status=1
+ fi
+ echo "-- For more information [see jdk17 report|${BUILD_URL}console]" >> "${OUTPUT_DIR}/commentfile"
+ exit "${status}"
+ '''
+ )
+ if (ret != 0) {
+ currentBuild.result = 'UNSTABLE'
+ }
+ }
+ }
+ }
+ }
+ post {
+ always {
+ script {
+ stash name: "jdk17-hadoop3-backwards-result-${HADOOP3_VERSION}", includes: "${OUTPUT_DIR_RELATIVE}/commentfile"
+ junit testResults: "${env.OUTPUT_DIR_RELATIVE}/**/target/**/TEST-*.xml", allowEmptyResults: true
+ // zip surefire reports.
+ sh '''#!/bin/bash -e
+ if [ ! -f "${OUTPUT_DIR}/commentfile" ]; then
+ echo "(x) {color:red}-1 jdk17 hadoop ${HADOOP3_VERSION} backward compatibility checks{color}" >"${OUTPUT_DIR}/commentfile"
+ echo "-- Something went wrong running this stage, please [check relevant console output|${BUILD_URL}/console]." >> "${OUTPUT_DIR}/commentfile"
+ fi
+ if [ -d "${OUTPUT_DIR}/archiver" ]; then
+ count=$(find "${OUTPUT_DIR}/archiver" -type f | wc -l)
+ if [[ 0 -ne ${count} ]]; then
+ echo "zipping ${count} archived files"
+ zip -q -m -r "${OUTPUT_DIR}/test_logs.zip" "${OUTPUT_DIR}/archiver"
+ else
+ echo "No archived files, skipping compressing."
+ fi
+ else
+ echo "No archiver directory, skipping compressing."
+ fi
+ '''
+ def logFile = "${env.OUTPUT_DIR_RELATIVE}/test_logs.zip"
+ if (fileExists(logFile)) {
+ sshPublisher(publishers: [
+ sshPublisherDesc(configName: 'Nightlies',
+ transfers: [
+ sshTransfer(remoteDirectory: "hbase/${JOB_NAME}/${BUILD_NUMBER}",
+ sourceFiles: "${env.OUTPUT_DIR_RELATIVE}/test_logs.zip"
+ )
+ ]
+ )
+ ])
+ sh '''#!/bin/bash -e
+ echo "Remove ${OUTPUT_DIR}/test_logs.zip for saving space"
+ rm -rf "${OUTPUT_DIR}/test_logs.zip"
+ python3 ${BASEDIR}/dev-support/gen_redirect_html.py "${ASF_NIGHTLIES_BASE}/${OUTPUT_DIR_RELATIVE}" > "${OUTPUT_DIR}/test_logs.html"
+ '''
+ }
+ archiveArtifacts artifacts: "${env.OUTPUT_DIR_RELATIVE}/*"
+ archiveArtifacts artifacts: "${env.OUTPUT_DIR_RELATIVE}/**/*"
+ publishHTML target: [
+ allowMissing: true,
+ keepAll: true,
+ alwaysLinkToLastBuild: true,
+ reportDir: "${env.OUTPUT_DIR_RELATIVE}",
+ reportFiles: 'console-report.html',
+ reportName: "JDK17 Nightly Build Report (Hadoop ${HADOOP3_VERSION} backwards compatibility)"
+ ]
+ } // script
+ } // always
+ } // post
+ } // matrix
+ } // stage ('backwards compatibility checks')
+ } // stages
+ post {
+ always {
+ script {
+ sh "printenv"
+ // wipe out all the output directories before unstashing
+ sh'''
+ echo "Clean up result directories"
+ rm -rf output-jdk17-hadoop3-backwards-*
+ '''
+ def results = []
+ for (hadoopVersion in getHadoopVersions(env.HADOOP_VERSIONS)) {
+ try {
+ unstash "jdk17-hadoop3-backwards-result-${hadoopVersion}"
+ results.add("output-jdk17-hadoop3-backwards-${hadoopVersion}/commentfile")
+ } catch (e) {
+ echo "unstash ${hadoopVersion} failed, ignore"
+ }
+ }
+ try {
+ def comment = "Results for branch ${env.BRANCH_NAME}\n"
+ comment += "\t[build ${currentBuild.displayName} on builds.a.o|${env.BUILD_URL}]: "
+ if (currentBuild.result == null || currentBuild.result == "SUCCESS") {
+ comment += "(/) *{color:green}+1 overall{color}*\n"
+ } else {
+ comment += "(x) *{color:red}-1 overall{color}*\n"
+ }
+ comment += "----\n"
+ comment += "Backwards compatibility checks:\n"
+ comment += results.collect { fileExists(file: it) ? readFile(file: it) : "" }.join("\n\n")
+
+ echo "[INFO] Comment:"
+ echo comment
+
+ def jiras = getJirasToComment(env.BRANCH_NAME, [])
+ if (jiras.isEmpty()) {
+ echo "[DEBUG] non-feature branch, checking change messages for jira keys."
+ jiras = getJirasToCommentFromChangesets(currentBuild)
+ }
+ jiras.each { currentIssue ->
+ jiraComment issueKey: currentIssue, body: comment
+ }
+ } catch (Exception exception) {
+ echo "Got exception: ${exception}"
+ echo " ${exception.getStackTrace()}"
+ }
+ }
+ }
+ }
+}
+
+@NonCPS
+List getHadoopVersions(String versions) {
+ return versions.split(',').collect { it.trim() }.findAll { it } as String[]
+}
+
+import org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper
+@NonCPS
+List getJirasToCommentFromChangesets(RunWrapper thisBuild) {
+ def seenJiras = []
+ thisBuild.changeSets.each { cs ->
+ cs.getItems().each { change ->
+ CharSequence msg = change.msg
+ echo "change: ${change}"
+ echo " ${msg}"
+ echo " ${change.commitId}"
+ echo " ${change.author}"
+ seenJiras = getJirasToComment(msg, seenJiras)
+ }
+ }
+ return seenJiras
+}
+
+@NonCPS
+List getJirasToComment(CharSequence source, List seen) {
+ source.eachMatch("HBASE-[0-9]+") { currentIssue ->
+ echo "[DEBUG] found jira key: ${currentIssue}"
+ if (currentIssue in seen) {
+ echo "[DEBUG] already commented on ${currentIssue}."
+ } else {
+ echo "[INFO] commenting on ${currentIssue}."
+ seen << currentIssue
+ }
+ }
+ return seen
+}
diff --git a/dev-support/hbase-personality.sh b/dev-support/hbase-personality.sh
index 46f08276c651..b5bd436064de 100755
--- a/dev-support/hbase-personality.sh
+++ b/dev-support/hbase-personality.sh
@@ -330,6 +330,9 @@ function personality_file_tests
## @audience private
## @stability evolving
## @param name of variable to set with maven arguments
+# NOTE: INCLUDE_TESTS_URL uses -Dtest= which conflicts with pom.xml patterns.
+# Do not use INCLUDE_TESTS_URL with profiles that define their own patterns
+# (e.g., runLargeTests-wave1, runLargeTests-wave2, runLargeTests-wave3).
function get_include_exclude_tests_arg
{
local __resultvar=$1
@@ -612,17 +615,17 @@ function hadoopcheck_rebuild
# TODO remove this on non 2.5 branches ?
yetus_info "Setting Hadoop 3 versions to test based on branch-2.5 rules"
if [[ "${QUICK_HADOOPCHECK}" == "true" ]]; then
- hbase_hadoop3_versions="3.2.4 3.3.6 3.4.0"
+ hbase_hadoop3_versions="3.2.4 3.3.6 3.4.2"
else
- hbase_hadoop3_versions="3.2.3 3.2.4 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.4.0"
+ hbase_hadoop3_versions="3.2.3 3.2.4 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.4.0 3.4.1 3.4.2"
fi
else
yetus_info "Setting Hadoop 3 versions to test based on branch-2.6+/master/feature branch rules"
# Isn't runnung these tests with the default Hadoop version redundant ?
if [[ "${QUICK_HADOOPCHECK}" == "true" ]]; then
- hbase_hadoop3_versions="3.3.6 3.4.0"
+ hbase_hadoop3_versions="3.3.6 3.4.2"
else
- hbase_hadoop3_versions="3.3.5 3.3.6 3.4.0"
+ hbase_hadoop3_versions="3.3.5 3.3.6 3.4.0 3.4.1 3.4.2"
fi
fi
@@ -852,6 +855,7 @@ function spotless_rebuild
{
local repostatus=$1
local logfile="${PATCH_DIR}/${repostatus}-spotless.txt"
+ local linecommentsfile="${PATCH_DIR}/${repostatus}-spotless-linecomments.txt"
if ! verify_needed_test spotless; then
return 0
@@ -869,12 +873,27 @@ function spotless_rebuild
count=$(${GREP} -c '\[ERROR\]' "${logfile}")
if [[ ${count} -gt 0 ]]; then
- add_vote_table -1 spotless "${repostatus} has ${count} errors when running spotless:check, run spotless:apply to fix."
- add_footer_table spotless "@@BASE@@/${repostatus}-spotless.txt"
+ # Generate file-level annotations for GitHub Actions
+ if [[ -n "${BUGLINECOMMENTS}" ]]; then
+ # Extract files with violations: lines like "[ERROR] src/path/to/file.java"
+ # with leading whitespace after [ERROR]
+ ${GREP} '^\[ERROR\][[:space:]]\+[^[:space:]]' "${logfile}" \
+ | ${SED} 's/^\[ERROR\][[:space:]]*//g' \
+ | while read -r file; do
+ echo "${file}:1:Spotless formatting required, run mvn spotless:apply"
+ done > "${linecommentsfile}"
+ if [[ -s "${linecommentsfile}" ]]; then
+ bugsystem_linecomments_queue spotless "${linecommentsfile}"
+ fi
+ fi
+
+ add_vote_table_v2 -1 spotless \
+ "@@BASE@@/${repostatus}-spotless.txt" \
+ "${repostatus} has ${count} errors when running spotless:check, run spotless:apply to fix."
return 1
fi
- add_vote_table +1 spotless "${repostatus} has no errors when running spotless:check."
+ add_vote_table_v2 +1 spotless "" "${repostatus} has no errors when running spotless:check."
return 0
}
diff --git a/dev-support/integration-test/integration-test.Jenkinsfile b/dev-support/integration-test/integration-test.Jenkinsfile
new file mode 100644
index 000000000000..d4490bc3311b
--- /dev/null
+++ b/dev-support/integration-test/integration-test.Jenkinsfile
@@ -0,0 +1,404 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+pipeline {
+ agent {
+ node {
+ label 'hbase'
+ }
+ }
+ triggers {
+ pollSCM('@daily')
+ }
+ options {
+ buildDiscarder(logRotator(numToKeepStr: '20'))
+ timeout (time: 16, unit: 'HOURS')
+ timestamps()
+ skipDefaultCheckout()
+ disableConcurrentBuilds()
+ }
+ environment {
+ HADOOP_VERSIONS = "2.10.2,3.2.4,3.3.5,3.3.6,3.4.0,3.4.1,3.4.2,3.4.3"
+ BASEDIR = "${env.WORKSPACE}/component"
+ }
+ parameters {
+ booleanParam(name: 'DEBUG', defaultValue: false, description: 'Produce a lot more meta-information.')
+ }
+ stages {
+ stage('scm-checkout') {
+ steps {
+ dir('component') {
+ checkout scm
+ }
+ }
+ }
+ // This is meant to mimic what a release manager will do to create RCs.
+ // See http://hbase.apache.org/book.html#maven.release
+ // TODO (HBASE-23870): replace this with invocation of the release tool
+ stage ('packaging test') {
+ steps {
+ sh '''#!/bin/bash -e
+ echo "Setting up directories"
+ rm -rf "output-srctarball" && mkdir "output-srctarball"
+ rm -rf "unpacked_src_tarball" && mkdir "unpacked_src_tarball"
+ rm -rf ".m2-for-repo" && mkdir ".m2-for-repo"
+ rm -rf ".m2-for-src" && mkdir ".m2-for-src"
+ '''
+ sh '''#!/bin/bash -e
+ rm -rf "output-srctarball/machine" && mkdir "output-srctarball/machine"
+ "${BASEDIR}/dev-support/gather_machine_environment.sh" "output-srctarball/machine"
+ echo "got the following saved stats in 'output-srctarball/machine'"
+ ls -lh "output-srctarball/machine"
+ '''
+ sh '''#!/bin/bash -e
+ echo "Checking the steps for an RM to make a source artifact, then a binary artifact."
+ docker build -t hbase-integration-test -f "${BASEDIR}/dev-support/docker/Dockerfile" .
+ docker run --rm -v "${WORKSPACE}":/hbase -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \
+ -u `id -u`:`id -g` -e JAVA_HOME="/usr/lib/jvm/java-17" --workdir=/hbase hbase-integration-test \
+ "component/dev-support/integration-test/source-artifact.sh" \
+ --intermediate-file-dir output-srctarball \
+ --unpack-temp-dir unpacked_src_tarball \
+ --maven-m2-initial .m2-for-repo \
+ --maven-m2-src-build .m2-for-src \
+ --clean-source-checkout \
+ component
+ if [ $? -eq 0 ]; then
+ echo '(/) {color:green}+1 source release artifact{color}\n-- See build output for details.' >output-srctarball/commentfile
+ else
+ echo '(x) {color:red}-1 source release artifact{color}\n-- See build output for details.' >output-srctarball/commentfile
+ exit 1
+ fi
+ '''
+ echo "make sure we have proper hbase tarballs under hbase-assembly"
+ sh '''#!/bin/bash -e
+ if [ 2 -ne $(ls -1 "${WORKSPACE}"/unpacked_src_tarball/hbase-assembly/target/hbase-*-bin.tar.gz | grep -v hadoop3 | wc -l) ]; then
+ echo '(x) {color:red}-1 testing binary artifact{color}\n-- source tarball did not produce the expected binaries.' >>output-srctarball/commentfile
+ exit 1
+ fi
+ if [[ "${BRANCH_NAME}" == *"branch-2"* ]]; then
+ if [ 2 -ne $(ls -1 "${WORKSPACE}"/unpacked_src_tarball/hbase-assembly/target/hbase-*-hadoop3-*-bin.tar.gz | wc -l) ]; then
+ echo '(x) {color:red}-1 testing binary artifact{color}\n-- source tarball did not produce the expected hadoop3 binaries.' >>output-srctarball/commentfile
+ exit 1
+ fi
+ fi
+ '''
+ stash name: 'hbase-install', includes: "unpacked_src_tarball/hbase-assembly/target/hbase-*-bin.tar.gz"
+ } // steps
+ post {
+ always {
+ script {
+ def srcFile = "${env.WORKSPACE}/output-srctarball/hbase-src.tar.gz"
+ if (fileExists(srcFile)) {
+ echo "upload hbase-src.tar.gz to nightlies"
+ sshPublisher(publishers: [
+ sshPublisherDesc(configName: 'Nightlies',
+ transfers: [
+ sshTransfer(remoteDirectory: "hbase/${JOB_NAME}/${BUILD_NUMBER}",
+ sourceFiles: srcFile
+ )
+ ]
+ )
+ ])
+ // remove the big src tarball, store the nightlies url in hbase-src.html
+ sh '''#!/bin/bash -e
+ SRC_TAR="${WORKSPACE}/output-srctarball/hbase-src.tar.gz"
+ echo "Remove ${SRC_TAR} for saving space"
+ rm -rf "${SRC_TAR}"
+ python3 ${BASEDIR}/dev-support/gen_redirect_html.py "${ASF_NIGHTLIES_BASE}/output-srctarball" > "${WORKSPACE}/output-srctarball/hbase-src.html"
+ '''
+ }
+ }
+ archiveArtifacts artifacts: 'output-srctarball/*'
+ archiveArtifacts artifacts: 'output-srctarball/**/*'
+ }
+ }
+ } // packaging test
+ stage ('integration test matrix') {
+ matrix {
+ agent {
+ node {
+ label 'hbase'
+ }
+ }
+ axes {
+ axis {
+ name 'HADOOP_VERSION'
+ // matrix does not support dynamic axis values, so here we need to keep align with the
+ // above environment
+ values "2.10.2","3.2.4","3.3.5","3.3.6","3.4.0","3.4.1","3.4.2","3.4.3"
+ }
+ }
+ environment {
+ BASEDIR = "${env.WORKSPACE}/component"
+ OUTPUT_DIR = "output-integration-hadoop-${env.HADOOP_VERSION}"
+ }
+ when {
+ expression {
+ if (HADOOP_VERSION == '2.10.2') {
+ // only branch-2/branch-2.x need to run against hadoop2, here we also includes
+ // HBASE-XXXXX-branch-2 feature branch
+ return env.BRANCH_NAME.contains('branch-2')
+ }
+ if (HADOOP_VERSION == '3.2.4') {
+ // only branch-2.5 need to run against hadoop 3.2.4, here we also includes
+ // HBASE-XXXXX-branch-2.5 feature branch
+ return env.BRANCH_NAME.contains('branch-2.5')
+ }
+ return true
+ }
+ }
+ stages {
+ stage('scm-checkout') {
+ steps {
+ sh '''#!/bin/bash -e
+ echo "Setting up directories"
+ rm -rf "${OUTPUT_DIR}" && mkdir "${OUTPUT_DIR}"
+ echo "(x) {color:red}-1 client integration test for ${HADOOP_VERSION}{color}\n-- Something went wrong with this stage, [check relevant console output|${BUILD_URL}/console]." >${OUTPUT_DIR}/commentfile
+ rm -rf "unpacked_src_tarball"
+ rm -rf "hbase-install" && mkdir "hbase-install"
+ rm -rf "hbase-client" && mkdir "hbase-client"
+ rm -rf "hadoop-install" && mkdir "hadoop-install"
+ rm -rf "hbase-hadoop3-install"
+ rm -rf "hbase-hadoop3-client"
+ # remove old hadoop tarballs in workspace
+ rm -rf hadoop-*.tar.gz
+ '''
+ dir('component') {
+ checkout scm
+ }
+ } // steps
+ } // scm-checkout
+ stage('install hadoop') {
+ steps {
+ dir("downloads-hadoop") {
+ sh '''#!/bin/bash -e
+ echo "Make sure we have a directory for downloading dependencies: $(pwd)"
+ '''
+ sh '''#!/bin/bash -e
+ echo "Ensure we have a copy of Hadoop ${HADOOP_VERSION}"
+ "${WORKSPACE}/component/dev-support/jenkins-scripts/cache-apache-project-artifact.sh" \
+ --working-dir "${WORKSPACE}/downloads-hadoop" \
+ --keys 'https://downloads.apache.org/hadoop/common/KEYS' \
+ --verify-tar-gz \
+ "${WORKSPACE}/hadoop-${HADOOP_VERSION}-bin.tar.gz" \
+ "hadoop/common/hadoop-${HADOOP_VERSION}/hadoop-${HADOOP_VERSION}.tar.gz"
+ for stale in $(ls -1 "${WORKSPACE}"/hadoop-*.tar.gz | grep -v ${HADOOP_VERSION}); do
+ echo "Delete stale hadoop cache ${stale}"
+ rm -rf $stale
+ done
+ artifact=$(ls -1 "${WORKSPACE}"/hadoop-${HADOOP_VERSION}-bin.tar.gz | head -n 1)
+ tar --strip-components=1 -xzf "${artifact}" -C "${WORKSPACE}/hadoop-install"
+ if [[ ${HADOOP_VERSION} == 3.* ]]; then
+ # we need to patch some files otherwise minicluster will fail to start, see MAPREDUCE-7471
+ ${BASEDIR}/dev-support/integration-test/patch-hadoop3.sh "${WORKSPACE}/hadoop-install"
+ fi
+ '''
+ } // dir
+ } // steps
+ } // install hadoop
+ stage('install hbase') {
+ steps {
+ unstash 'hbase-install'
+ sh'''#!/bin/bash -e
+ install_artifact=$(ls -1 "${WORKSPACE}"/unpacked_src_tarball/hbase-assembly/target/hbase-*-bin.tar.gz | grep -v client-bin | grep -v hadoop3)
+ tar --strip-component=1 -xzf "${install_artifact}" -C "hbase-install"
+ client_artifact=$(ls -1 "${WORKSPACE}"/unpacked_src_tarball/hbase-assembly/target/hbase-*-client-bin.tar.gz | grep -v hadoop3)
+ tar --strip-component=1 -xzf "${client_artifact}" -C "hbase-client"
+ if ls "${WORKSPACE}"/unpacked_src_tarball/hbase-assembly/target/hbase-*-hadoop3-*-bin.tar.gz &>/dev/null; then
+ echo "hadoop3 artifacts available, unpacking the hbase hadoop3 bin tarball into 'hbase-hadoop3-install' and the client hadoop3 tarball into 'hbase-hadoop3-client'"
+ mkdir hbase-hadoop3-install
+ mkdir hbase-hadoop3-client
+ hadoop3_install_artifact=$(ls -1 "${WORKSPACE}"/unpacked_src_tarball/hbase-assembly/target/hbase-*-hadoop3-*-bin.tar.gz | grep -v client-bin)
+ tar --strip-component=1 -xzf "${hadoop3_install_artifact}" -C "hbase-hadoop3-install"
+ hadoop3_client_artifact=$(ls -1 "${WORKSPACE}"/unpacked_src_tarball/hbase-assembly/target/hbase-*-hadoop3-*-client-bin.tar.gz)
+ tar --strip-component=1 -xzf "${hadoop3_client_artifact}" -C "hbase-hadoop3-client"
+ fi
+ '''
+ } // steps
+ }
+ stage('integration test ') {
+ steps {
+ sh '''#!/bin/bash -e
+ hbase_install_dir="hbase-install"
+ hbase_client_dir="hbase-client"
+ if [[ ${HADOOP_VERSION} == 3.* ]] && [[ -d "hbase-hadoop3-install" ]]; then
+ echo "run hadoop3 client integration test against hbase hadoop3 binaries"
+ hbase_install_dir="hbase-hadoop3-install"
+ hbase_client_dir="hbase-hadoop3-client"
+ fi
+ java_home="/usr/lib/jvm/java-17"
+ hadoop_opts="--add-opens java.base/java.lang=ALL-UNNAMED"
+ if [[ ${HADOOP_VERSION} == 2.* ]]; then
+ java_home="/usr/lib/jvm/java-8"
+ hadoop_opts=""
+ fi
+ echo "Attempting to run an instance on top of Hadoop ${HADOOP_VERSION}."
+ # Create working dir
+ rm -rf "${OUTPUT_DIR}/non-shaded" && mkdir "${OUTPUT_DIR}/non-shaded"
+ docker build -t hbase-integration-test -f "${BASEDIR}/dev-support/docker/Dockerfile" .
+ docker run --rm -v "${WORKSPACE}":/hbase -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \
+ -u `id -u`:`id -g` -e JAVA_HOME="${java_home}" \
+ -e HADOOP_OPTS="${hadoop_opts}" \
+ --workdir=/hbase hbase-integration-test \
+ component/dev-support/integration-test/pseudo-distributed-test.sh \
+ --single-process \
+ --working-dir ${OUTPUT_DIR}/non-shaded \
+ --hbase-client-install ${hbase_client_dir} \
+ ${hbase_install_dir} \
+ hadoop-install/bin/hadoop \
+ hadoop-install/share/hadoop/yarn/timelineservice \
+ hadoop-install/share/hadoop/yarn/test/hadoop-yarn-server-tests-*-tests.jar \
+ hadoop-install/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-*-tests.jar \
+ hadoop-install/bin/mapred \
+ >${OUTPUT_DIR}/hadoop.log 2>&1
+ if [ $? -ne 0 ]; then
+ echo "(x) {color:red}-1 client integration test for ${HADOOP_VERSION}{color}\n--Failed when running client tests on top of Hadoop ${HADOOP_VERSION}. [see log for details|${BUILD_URL}/artifact/${OUTPUT_DIR}/hadoop.log]. (note that this means we didn't check the Hadoop ${HADOOP_VERSION} shaded client)" >${OUTPUT_DIR}/commentfile
+ exit 2
+ fi
+ echo "(/) {color:green}+1 client integration test for ${HADOOP_VERSION} {color}" >${OUTPUT_DIR}/commentfile
+ if [[ ${HADOOP_VERSION} == 2.* ]] || [[ ${HADOOP_VERSION} == 3.2.* ]]; then
+ echo "skip running shaded hadoop client test for ${HADOOP_VERSION}"
+ exit 0
+ fi
+ # Create working dir
+ rm -rf "${OUTPUT_DIR}/shaded" && mkdir "${OUTPUT_DIR}/shaded"
+ echo "Attempting to run an instance on top of Hadoop ${HADOOP_VERSION}, relying on the Hadoop client artifacts for the example client program."
+ docker run --rm -v "${WORKSPACE}":/hbase -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \
+ -u `id -u`:`id -g` -e JAVA_HOME="${java_home}" \
+ -e HADOOP_OPTS="${hadoop_opts}" \
+ --workdir=/hbase hbase-integration-test \
+ component/dev-support/integration-test/pseudo-distributed-test.sh \
+ --single-process \
+ --hadoop-client-classpath hadoop-install/share/hadoop/client/hadoop-client-api-*.jar:hadoop-install/share/hadoop/client/hadoop-client-runtime-*.jar \
+ --working-dir ${OUTPUT_DIR}/shaded \
+ --hbase-client-install ${hbase_client_dir} \
+ ${hbase_install_dir} \
+ hadoop-install/bin/hadoop \
+ hadoop-install/share/hadoop/yarn/timelineservice \
+ hadoop-install/share/hadoop/yarn/test/hadoop-yarn-server-tests-*-tests.jar \
+ hadoop-install/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-*-tests.jar \
+ hadoop-install/bin/mapred \
+ >${OUTPUT_DIR}/hadoop-shaded.log 2>&1
+ if [ $? -ne 0 ]; then
+ echo "(x) {color:red}-1 client integration testfor ${HADOOP_VERSION}{color}\n--Failed when running client tests on top of Hadoop ${HADOOP_VERSION} using Hadoop's shaded client. [see log for details|${BUILD_URL}/artifact/${OUTPUT_DIR}/hadoop-shaded.log]." >> ${OUTPUT_DIR}/commentfile
+ exit 2
+ fi
+ echo "(/) {color:green}+1 client integration test for ${HADOOP_VERSION} with shaded hadoop client{color}" >> ${OUTPUT_DIR}/commentfile
+ '''
+ } // steps
+ post {
+ always {
+ stash name: "test-result-${env.HADOOP_VERSION}", includes: "${env.OUTPUT_DIR}/commentfile"
+ archiveArtifacts artifacts: "${env.OUTPUT_DIR}/*"
+ archiveArtifacts artifacts: "${env.OUTPUT_DIR}/**/*"
+ } // always
+ } // post
+ } // integration test
+ } // stages
+ } // matrix
+ } // integration test matrix
+ } // stages
+ post {
+ always {
+ script {
+ sh "printenv"
+ // wipe out all the output directories before unstashing
+ sh'''
+ echo "Clean up result directories"
+ rm -rf output-srctarball
+ rm -rf output-integration-hadoop-*
+ '''
+ def results = []
+ results.add('output-srctarball/commentfile')
+ for (hadoopVersion in getHadoopVersions(env.HADOOP_VERSIONS)) {
+ try {
+ unstash "test-result-${hadoopVersion}"
+ results.add("output-integration-hadoop-${hadoopVersion}/commentfile")
+ } catch (e) {
+ echo "unstash ${hadoopVersion} failed, ignore"
+ }
+ }
+ echo env.BRANCH_NAME
+ echo env.BUILD_URL
+ echo currentBuild.result
+ echo currentBuild.durationString
+ def comment = "Results for branch ${env.BRANCH_NAME}\n"
+ comment += "\t[build ${currentBuild.displayName} on builds.a.o|${env.BUILD_URL}]: "
+ if (currentBuild.result == null || currentBuild.result == "SUCCESS") {
+ comment += "(/) *{color:green}+1 overall{color}*\n"
+ } else {
+ comment += "(x) *{color:red}-1 overall{color}*\n"
+ // Ideally get the committer our of the change and @ mention them in the per-jira comment
+ }
+ comment += "----\ndetails (if available):\n\n"
+ echo ""
+ echo "[DEBUG] trying to aggregate step-wise results"
+ comment += results.collect { fileExists(file: it) ? readFile(file: it) : "" }.join("\n\n")
+ echo "[INFO] Comment:"
+ echo comment
+ echo ""
+ echo "[DEBUG] checking to see if feature branch"
+ def jiras = getJirasToComment(env.BRANCH_NAME, [])
+ if (jiras.isEmpty()) {
+ echo "[DEBUG] non-feature branch, checking change messages for jira keys."
+ echo "[INFO] There are ${currentBuild.changeSets.size()} change sets."
+ jiras = getJirasToCommentFromChangesets(currentBuild)
+ }
+ jiras.each { currentIssue ->
+ jiraComment issueKey: currentIssue, body: comment
+ }
+ } // script
+ } // always
+ } // post
+}
+
+@NonCPS
+List getHadoopVersions(String versions) {
+ return versions.split(',').collect { it.trim() }.findAll { it } as String[]
+}
+
+import org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper
+@NonCPS
+List getJirasToCommentFromChangesets(RunWrapper thisBuild) {
+ def seenJiras = []
+ thisBuild.changeSets.each { cs ->
+ cs.getItems().each { change ->
+ CharSequence msg = change.msg
+ echo "change: ${change}"
+ echo " ${msg}"
+ echo " ${change.commitId}"
+ echo " ${change.author}"
+ echo ""
+ seenJiras = getJirasToComment(msg, seenJiras)
+ }
+ }
+ return seenJiras
+}
+
+@NonCPS
+List getJirasToComment(CharSequence source, List seen) {
+ source.eachMatch("HBASE-[0-9]+") { currentIssue ->
+ echo "[DEBUG] found jira key: ${currentIssue}"
+ if (currentIssue in seen) {
+ echo "[DEBUG] already commented on ${currentIssue}."
+ } else {
+ echo "[INFO] commenting on ${currentIssue}."
+ seen << currentIssue
+ }
+ }
+ return seen
+}
+
diff --git a/dev-support/patch-hadoop3.sh b/dev-support/integration-test/patch-hadoop3.sh
similarity index 83%
rename from dev-support/patch-hadoop3.sh
rename to dev-support/integration-test/patch-hadoop3.sh
index fed5a535bcdd..b4c51ca9487d 100755
--- a/dev-support/patch-hadoop3.sh
+++ b/dev-support/integration-test/patch-hadoop3.sh
@@ -20,5 +20,5 @@
hadoop_dir=$1
sed -i "s/HADOOP_TOOLS_DIR=\${HADOOP_TOOLS_DIR:-\"share\/hadoop\/tools\"}/HADOOP_TOOLS_DIR=\${HADOOP_TOOLS_DIR:-\"\$HADOOP_TOOLS_HOME\/share\/hadoop\/tools\"}/g" "$hadoop_dir/libexec/hadoop-functions.sh"
-sed -i "/hadoop_add_classpath \"\${junitjar}\"/a mockitojar=\$(echo \"\${HADOOP_TOOLS_LIB_JARS_DIR}\"\/mockito-core-[0-9]*.jar)\nhadoop_add_classpath \"\${mockitojar}\"" "$hadoop_dir/bin/mapred"
+sed -i "/HADOOP_CLASSNAME=org.apache.hadoop.mapreduce.MiniHadoopClusterManager/a mockitojar=\$(echo \"\${HADOOP_TOOLS_LIB_JARS_DIR}\"\/mockito-core-[0-9]*.jar)\nhadoop_add_classpath \"\${mockitojar}\"" "$hadoop_dir/bin/mapred"
curl https://repo1.maven.org/maven2/org/mockito/mockito-core/2.28.2/mockito-core-2.28.2.jar -o "$hadoop_dir/share/hadoop/tools/lib/mockito-core-2.28.2.jar"
diff --git a/dev-support/hbase_nightly_pseudo-distributed-test.sh b/dev-support/integration-test/pseudo-distributed-test.sh
similarity index 96%
rename from dev-support/hbase_nightly_pseudo-distributed-test.sh
rename to dev-support/integration-test/pseudo-distributed-test.sh
index 75f0ab9a9f8d..d9da9a38ef09 100755
--- a/dev-support/hbase_nightly_pseudo-distributed-test.sh
+++ b/dev-support/integration-test/pseudo-distributed-test.sh
@@ -308,7 +308,11 @@ fi
if [ "${hadoop_version%.*.*}" -gt 2 ]; then
echo "Verifying configs"
- "${hadoop_exec}" --config "${working_dir}/hbase-conf/" conftest
+ hadoop_conf_files=""
+ for f in "${working_dir}"/hbase-conf/*-site.xml; do
+ hadoop_conf_files="$hadoop_conf_files -conffile $f"
+ done
+ "${hadoop_exec}" --config "${working_dir}/hbase-conf/" conftest $hadoop_conf_files
fi
if [ -n "${clean}" ]; then
@@ -322,6 +326,14 @@ echo "Listing HDFS contents"
redirect_and_run "${working_dir}/hadoop_cluster_smoke" \
"${hadoop_exec}" --config "${working_dir}/hbase-conf/" fs -ls -R /
+if [ "${hadoop_version%.*.*}" -gt 2 ]; then
+ # for now, all hbase branches are compiled with hadoop 3.4.x when using hadoop-3.0 profile, where
+ # the protobuf library has been shaded and relocated, so we always need to use ProtobufRpcEngine2
+ # at hbase side, even if the hadoop server side uses ProtobufRpcEngine, so here we will remove the
+ # config value to let the hadoop code pick the right rpc engine
+ sed -i "/.*ProtobufRpcEngine.*<\/property>/d" "${working_dir}/hbase-conf/core-site.xml"
+fi
+
echo "Starting up HBase"
HBASE_CONF_DIR="${working_dir}/hbase-conf/" HBASE_LOG_DIR="${working_dir}" "${component_install}/bin/start-hbase.sh"
@@ -413,7 +425,7 @@ HADOOP_CLASSPATH="${hbase_dep_classpath}" redirect_and_run "${working_dir}/mr-im
EOF
echo "Verifying row count from import."
-import_rowcount=$(echo 'count "test:example"' | "${hbase_client}/bin/hbase" --config "${working_dir}/hbase-conf/" shell --noninteractive 2>/dev/null | tail -n 1)
+import_rowcount=$(echo 'count "test:example"' | "${hbase_client}/bin/hbase" --config "${working_dir}/hbase-conf/" shell --noninteractive 2>/dev/null | grep "row(s)" | awk '{print $1}')
if [ ! "${import_rowcount}" -eq 48 ]; then
echo "ERROR: Instead of finding 48 rows, we found ${import_rowcount}."
exit 2
@@ -526,7 +538,7 @@ echo "Checking on results of example program."
EOF
echo "Verifying row count from example."
-example_rowcount=$(echo 'count "test:example"' | "${hbase_client}/bin/hbase" --config "${working_dir}/hbase-conf/" shell --noninteractive 2>/dev/null | tail -n 1)
+example_rowcount=$(echo 'count "test:example"' | "${hbase_client}/bin/hbase" --config "${working_dir}/hbase-conf/" shell --noninteractive 2>/dev/null | grep "row(s)" | awk '{print $1}')
if [ "${example_rowcount}" -gt "1050" ]; then
echo "Found ${example_rowcount} rows, which is enough to cover 48 for import, 1000 example's use of user table regions, 2 for example's use of meta/namespace regions, and 1 for example's count record"
else
diff --git a/dev-support/hbase_nightly_source-artifact.sh b/dev-support/integration-test/source-artifact.sh
similarity index 98%
rename from dev-support/hbase_nightly_source-artifact.sh
rename to dev-support/integration-test/source-artifact.sh
index 372c39b8f887..1b54aaae0e3f 100755
--- a/dev-support/hbase_nightly_source-artifact.sh
+++ b/dev-support/integration-test/source-artifact.sh
@@ -34,6 +34,8 @@ function usage {
exit 1
}
+set -e
+
MVN="mvn"
if ! command -v mvn &>/dev/null; then
MVN=$MAVEN_HOME/bin/mvn
@@ -218,8 +220,10 @@ function build_tarball {
cd "${unpack_dir}"
-${MVN} -Dmaven.repo.local="${m2_tarbuild}" help:active-profiles | grep -q hadoop-3.0
-if [ $? -ne 0 ]; then
+if ${MVN} -Dmaven.repo.local="${m2_tarbuild}" help:active-profiles | grep -q hadoop-3.0; then
+ echo "The hadoop-3.0 profile is activated by default, build a default tarball."
+ build_tarball 0
+else
echo "The hadoop-3.0 profile is not activated by default, build a default tarball first."
# use java 8 to build with hadoop2
JAVA_HOME="/usr/lib/jvm/java-8" build_tarball 0
@@ -236,7 +240,4 @@ if [ $? -ne 0 ]; then
fi
# move tarballs back
mv "${unpack_dir}"/hbase-*-bin.tar.gz "${unpack_dir}"/hbase-assembly/target/
-else
- echo "The hadoop-3.0 profile is activated by default, build a default tarball."
- build_tarball 0
fi
diff --git a/dev-support/jenkins_precommit_github_yetus.sh b/dev-support/jenkins_precommit_github_yetus.sh
index 2d8421fd756d..05ac0f89a404 100755
--- a/dev-support/jenkins_precommit_github_yetus.sh
+++ b/dev-support/jenkins_precommit_github_yetus.sh
@@ -31,7 +31,6 @@ declare -i missing_env=0
declare -a required_envs=(
# these ENV variables define the required API with Jenkinsfile_GitHub
"ARCHIVE_PATTERN_LIST"
- "BUILD_URL_ARTIFACTS"
"DOCKERFILE"
"GITHUB_PASSWORD"
"GITHUB_USER"
@@ -39,7 +38,6 @@ declare -a required_envs=(
"PLUGINS"
"SET_JAVA_HOME"
"SOURCEDIR"
- "TESTS_FILTER"
"YETUSDIR"
"AUTHOR_IGNORE_LIST"
"BLANKS_EOL_IGNORE_FILE"
@@ -53,6 +51,12 @@ for required_env in "${required_envs[@]}"; do
fi
done
+# BUILD_URL_ARTIFACTS is required for Jenkins but set in personality for GitHub Actions
+if [[ "${GITHUB_ACTIONS}" != "true" ]] && [[ -z "${BUILD_URL_ARTIFACTS}" ]]; then
+ echo "[ERROR] Required environment variable 'BUILD_URL_ARTIFACTS' is not set."
+ missing_env=${missing_env}+1
+fi
+
if [ ${missing_env} -gt 0 ]; then
echo "[ERROR] Please set the required environment variables before invoking. If this error is " \
"on Jenkins, then please file a JIRA about the error."
@@ -91,7 +95,11 @@ YETUS_ARGS+=("--console-report-file=${PATCHDIR}/console.txt")
YETUS_ARGS+=("--html-report-file=${PATCHDIR}/report.html")
# enable writing back to Github
YETUS_ARGS+=("--github-token=${GITHUB_PASSWORD}")
-YETUS_ARGS+=("--github-write-comment")
+# GitHub Actions fork PRs cannot write comments (GITHUB_TOKEN has no PR write permission)
+# Jenkins can write comments via its own credentials
+if [[ "${GITHUB_ACTIONS}" != "true" ]]; then
+ YETUS_ARGS+=("--github-write-comment")
+fi
# auto-kill any surefire stragglers during unit test runs
YETUS_ARGS+=("--reapermode=kill")
# set relatively high limits for ASF machines
@@ -103,7 +111,9 @@ YETUS_ARGS+=("--spotbugs-strict-precheck")
# rsync these files back into the archive dir
YETUS_ARGS+=("--archive-list=${ARCHIVE_PATTERN_LIST}")
# URL for user-side presentation in reports and such to our artifacts
-YETUS_ARGS+=("--build-url-artifacts=${BUILD_URL_ARTIFACTS}")
+if [[ -n "${BUILD_URL_ARTIFACTS}" ]]; then
+ YETUS_ARGS+=("--build-url-artifacts=${BUILD_URL_ARTIFACTS}")
+fi
# plugins to enable
YETUS_ARGS+=("--plugins=${PLUGINS},-findbugs")
# run in docker mode and specifically point to our
@@ -115,15 +125,17 @@ YETUS_ARGS+=("--java-home=${SET_JAVA_HOME}")
YETUS_ARGS+=("--author-ignore-list=${AUTHOR_IGNORE_LIST}")
YETUS_ARGS+=("--blanks-eol-ignore-file=${BLANKS_EOL_IGNORE_FILE}")
YETUS_ARGS+=("--blanks-tabs-ignore-file=${BLANKS_TABS_IGNORE_FILE}*")
-YETUS_ARGS+=("--tests-filter=${TESTS_FILTER}")
+if [[ -n "${TESTS_FILTER}" ]]; then
+ YETUS_ARGS+=("--tests-filter=${TESTS_FILTER}")
+fi
YETUS_ARGS+=("--personality=${SOURCEDIR}/dev-support/hbase-personality.sh")
YETUS_ARGS+=("--quick-hadoopcheck")
if [[ "${SKIP_ERRORPRONE}" = "true" ]]; then
# skip error prone
YETUS_ARGS+=("--skip-errorprone")
fi
-# effectively treat dev-support as a custom maven module
-YETUS_ARGS+=("--skip-dirs=dev-support")
+# Exclude non-code directories from module detection to avoid triggering full builds
+YETUS_ARGS+=("--skip-dirs=dev-support,.github,bin,conf")
# For testing with specific hadoop version. Activates corresponding profile in maven runs.
if [[ -n "${HADOOP_PROFILE}" ]]; then
# Master has only Hadoop3 support. We don't need to activate any profile.
@@ -156,6 +168,10 @@ fi
if [[ -n "${JAVA8_HOME}" ]]; then
YETUS_ARGS+=("--java8-home=${JAVA8_HOME}")
fi
+# Test profile for running specific test categories (e.g., runDevTests, runLargeTests-wave1)
+if [[ -n "${TEST_PROFILE}" ]]; then
+ YETUS_ARGS+=("--test-profile=${TEST_PROFILE}")
+fi
echo "Launching yetus with command line:"
echo "${TESTPATCHBIN} ${YETUS_ARGS[*]}"
diff --git a/dev-support/spotbugs-exclude.xml b/dev-support/spotbugs-exclude.xml
index 2f0684eff4d7..17b8d2cbdedd 100644
--- a/dev-support/spotbugs-exclude.xml
+++ b/dev-support/spotbugs-exclude.xml
@@ -271,4 +271,16 @@
+
+
+
+
+
+
+
+
+
diff --git a/dev-support/yetus_console_to_md.py b/dev-support/yetus_console_to_md.py
new file mode 100644
index 000000000000..bee5512eec71
--- /dev/null
+++ b/dev-support/yetus_console_to_md.py
@@ -0,0 +1,522 @@
+#!/usr/bin/env python3
+##
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Convert Apache Yetus console output to Markdown format.
+"""
+import os
+import re
+import sys
+from io import TextIOWrapper
+from pathlib import Path
+from typing import Dict, List, Optional, Tuple
+
+# Vote to emoji mapping
+VOTE_EMOJI = {
+ '+1': '✅',
+ '-1': '❌',
+ '0': '🆗',
+ '+0': '🆗',
+ '-0': '⚠️'
+}
+
+
+def convert_vote(vote: str) -> str:
+ """Convert vote string to emoji."""
+ return VOTE_EMOJI.get(vote, vote)
+
+
+def is_runtime(text: str) -> bool:
+ """Check if text is a runtime like '41m 24s'."""
+ return bool(re.match(r'^\d+m\s+\d+s$', text))
+
+
+def parse_table_row(line: str) -> Tuple[str, str, str, str]:
+ """
+ Parse a table row and return tuple of cell values.
+ Returns exactly 4 columns: (vote, subsystem, runtime, comment)
+ """
+ parts = line.split('|')
+ # Remove first empty element (from leading |)
+ parts = parts[1:] if len(parts) > 1 else []
+
+ # Take first 4 columns and strip whitespace
+ result: List[str] = [p.strip() for p in parts[:4]]
+
+ # Pad to 4 columns if needed
+ while len(result) < 4:
+ result.append('')
+
+ return result[0], result[1], result[2], result[3]
+
+
+def is_results_section_start(line: str) -> bool:
+ """Check if line indicates the start of Results section."""
+ return bool(re.search(r'^\[\w+] Results:', line.strip()))
+
+
+def is_tests_run_summary(line: str) -> bool:
+ """Check if line is the Tests run summary line."""
+ return bool(re.search(r'^\[\w+] Tests run:', line.strip()))
+
+
+def parse_results_section(
+ f: TextIOWrapper,
+ failures: List[str],
+ flakes: List[str],
+ errors: List[str]
+) -> None:
+ """
+ Parse the Results section within a patch-unit file.
+ """
+ current_error_type = None
+ while line := f.readline():
+ stripped = line.strip()
+
+ # Section end markers
+ if is_tests_run_summary(line):
+ return
+
+ # Detect error type sections
+ if re.search(r'^\[\w+] Failures:', stripped):
+ current_error_type = failures
+ elif re.search(r'^\[\w+] Flakes:', stripped):
+ current_error_type = flakes
+ elif re.search(r'^\[\w+] Errors:', stripped):
+ current_error_type = errors
+ else:
+ # Parse test entries
+ if current_error_type is not None:
+ test_match = re.search(
+ r'^\[\w+]\s+((?:org\.)?\S+\.(?:\w+\.)*\w+\.\w+)',
+ stripped
+ )
+ if test_match:
+ test_name = test_match.group(1)
+ if 'test' in test_name.lower():
+ current_error_type.append(test_name)
+
+
+def skip_to_results_section(f: TextIOWrapper) -> bool:
+ """
+ Skip the io stream to the Results section.
+ After calling this method, the TextIOWrapper will locate at the next line of "Results: "
+
+ Returns:
+ True if we find a results section, False if we have reached the EOF
+ """
+ while line := f.readline():
+ if is_results_section_start(line):
+ return True
+ return False
+
+
+def scan_all_tests(dir: Path) -> Dict[str, str]:
+ """
+ Scan the archiver dir to find all the tests and their module
+
+ Returns:
+ Dict mapping test name to module name
+ """
+ module = None
+ module_to_test_name = {}
+ for dirpath, _, filenames in os.walk(dir):
+ if len(filenames) > 0:
+ # /archiver//target/surefire-reports
+ module = dirpath.split(os.sep)[-3]
+ for filename in filenames:
+ match = re.match(r'(org\.apache\.[^-]+)\.txt', filename)
+ if match:
+ module_to_test_name[match.group(1)] = module
+ return module_to_test_name
+
+
+def parse_patch_unit_file(
+ file_path: Path,
+ failures: List[str],
+ flakes: List[str],
+ errors: List[str]
+) -> None:
+ """
+ Parse a patch-unit-*.txt file and extract failed tests by module.
+ """
+ with open(file_path, 'r') as f:
+ while skip_to_results_section(f):
+ parse_results_section(f, failures, flakes, errors)
+
+
+def get_module(test_name: str, test_name_to_module: Dict[str, str]) -> str:
+ rindex_of_bracket = test_name.rfind('[')
+ if rindex_of_bracket > 0:
+ # parameterized test, remove the tailing parameters
+ test_name = test_name[:rindex_of_bracket]
+
+ module = test_name_to_module.get(test_name)
+ if module:
+ return module
+
+ # usually the failed test name has the method name suffix, but the test_name_to_module only
+ # contains class name, so let's try to remove the last part and try again
+ rindex_of_dot = test_name.rfind('.')
+ if rindex_of_dot > 0:
+ test_name = test_name[:rindex_of_dot]
+
+ module = test_name_to_module.get(test_name)
+ if module:
+ return module
+ return 'default'
+
+
+def increase(module_to_count: Dict[str, int], module: str) -> None:
+ if module in module_to_count:
+ module_to_count[module] += 1
+ else:
+ module_to_count[module] = 1
+
+
+def add_to_details(test_name: str, module: str, error_type: str,
+ details: Dict[str, Dict[str, List[str]]]) -> None:
+ if module not in details:
+ error_type_to_tests = {}
+ details[module] = error_type_to_tests
+ else:
+ error_type_to_tests = details[module]
+
+ if error_type in error_type_to_tests:
+ error_type_to_tests[error_type].append(test_name)
+ else:
+ error_type_to_tests[error_type] = [test_name]
+
+
+def process_failed_tests(
+ error_type: str,
+ failed_tests: List[str],
+ module_to_test_name: Dict[str, str],
+ counts: Dict[str, Dict[str, int]],
+ details: Dict[str, Dict[str, List[str]]]
+) -> None:
+ for test_name in failed_tests:
+ module = get_module(test_name, module_to_test_name)
+ increase(counts[error_type], module)
+ add_to_details(test_name, module, error_type, details)
+
+
+def aggregate_failed_tests(yetus_dir: Path) -> Tuple[
+ Dict[str, Dict[str, int]], Dict[str, Dict[str, List[str]]]]:
+ """
+ Aggregate failed tests from all patch-unit-*.txt files.
+
+ Returns:
+ Tuple of:
+ - counts: {error_type: {module: count}}
+ - details: {module: {error_type: [test_names]}}
+ """
+ patch_files = list(yetus_dir.glob('patch-unit-*.txt'))
+
+ if not patch_files:
+ return {}, {}
+
+ # Aggregate results from all files
+ failures = []
+ flakes = []
+ errors = []
+
+ for patch_file in patch_files:
+ parse_patch_unit_file(patch_file, failures, flakes, errors)
+
+ if not failures and not flakes and not errors:
+ return {}, {}
+
+ counts = {'Failures': {}, 'Flakes': {}, 'Errors': {}}
+ details = {}
+ module_to_test_name = scan_all_tests(yetus_dir / 'archiver')
+ process_failed_tests('Failures', failures, module_to_test_name, counts, details)
+ process_failed_tests('Flakes', flakes, module_to_test_name, counts, details)
+ process_failed_tests('Errors', errors, module_to_test_name, counts, details)
+
+ return dict(counts), dict(details)
+
+
+def generate_failed_tests_table(
+ counts: Dict[str, Dict[str, int]],
+ details: Dict[str, Dict[str, List[str]]]
+) -> List[str]:
+ """Generate the Failed Tests HTML table."""
+ total_failures = sum(sum(m.values()) for m in counts.values())
+ if total_failures == 0:
+ return []
+
+ content = [
+ '\n## Failed Tests\n\n',
+ '
\n',
+ '
Error Type
Count
Module
Tests
\n',
+ '\n'
+ ]
+
+ error_types = ['Failures', 'Flakes', 'Errors']
+
+ for error_type in error_types:
+ if error_type not in counts:
+ continue
+
+ modules = counts[error_type]
+ total_count = sum(modules.values())
+ num_modules = len(modules)
+
+ first_row = True
+ for module in sorted(modules.keys()):
+ tests = details.get(module, {}).get(error_type, [])
+ tests_str = ' '.join(sorted(set(tests))) if tests else ''
+
+ if first_row:
+ content.append(
+ f'