Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
acd4109
feat(import): add snapshot import helper script and usage documentation
tianlei2 Jun 22, 2026
1e2551c
Fix JDK 21+ compatibility, restore path directory constraints, and ne…
tianlei2 Jun 23, 2026
38715e3
Update SNAPSHOT_IMPORT_USAGE.md troubleshooting section for JVM_OPTS
tianlei2 Jun 23, 2026
7206688
refactor(import): relocate helper script to bin/, make path dynamic, …
tianlei2 Jun 24, 2026
7d17721
Update bigtable-dataflow-parent/bigtable-beam-import/bin/run-snapshot…
tianlei2 Jun 24, 2026
883fcb5
Update bigtable-dataflow-parent/bigtable-beam-import/bin/run-snapshot…
tianlei2 Jun 24, 2026
8e2a325
Update bigtable-dataflow-parent/bigtable-beam-import/bin/run-snapshot…
tianlei2 Jun 24, 2026
5c60674
feat(import): merge remote PR validations & concurrency optimizations…
tianlei2 Jun 24, 2026
c137f46
docs(import): update SNAPSHOT_IMPORT_USAGE.md to document required vs…
tianlei2 Jun 24, 2026
a4d3d13
style(import): update outdated sharding comment to reflect 4 parallel…
tianlei2 Jun 24, 2026
5f032c7
docs(import): update SNAPSHOT_IMPORT_USAGE.md to describe the 4 paral…
tianlei2 Jun 24, 2026
45288bc
refactor(import): optimize JAR detection to always select the newest …
tianlei2 Jun 24, 2026
555ba00
fix(import): pass service account args to restore step and quote vari…
tianlei2 Jun 24, 2026
403d35a
fix(import): track background job PIDs and propagate exit status fail…
tianlei2 Jun 24, 2026
3c6befd
fix(import): double-quote variables in the standard range mode java c…
tianlei2 Jun 24, 2026
724dbcb
fix(import): sanitize BUCKET env variable by stripping gs:// prefix a…
tianlei2 Jun 24, 2026
9677db0
feat(import): make job prefix and execution parameters configurable, …
tianlei2 Jun 24, 2026
8b699a3
fix(import): add exit status checks and shard index validation to run…
tianlei2 Jun 25, 2026
29c9a85
refactor(import): export env vars, add interruption cleanup trap, and…
tianlei2 Jun 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# HBase Snapshot Import Helper Script Usage

This document describes the environment variables used by the `bin/run-snapshot-import.sh` script to automate HBase snapshot imports into Cloud Bigtable using Dataflow.

## Environment Variables

The script relies on the following environment variables. You should set them before executing the script.

| Variable | Status | Description | Default / Example |
| :--- | :--- | :--- | :--- |
| `PROJECT_ID` | **Required** | The Google Cloud Project ID where the Bigtable instance and Dataflow jobs reside. | `your-project-id` |
| `INSTANCE_ID` | **Required** | The Bigtable Instance ID to import data into. | `your-instance-id` |
| `BUCKET` | **Required** | The GCS bucket name. The script automatically strips any leading gs:// or trailing slashes for robust path construction. | `your-gcs-bucket` |
| `REGION` | **Required** | The GCP region to run the Dataflow jobs in. | `us-central1` |
| `TABLE_NAME` | **Required** | The target Bigtable table name. | `your-table-name` |
| `SNAPSHOT_NAME` | **Required** | The name of the HBase snapshot to import. | `your-snapshot-name` |
| `SNAPSHOT_SOURCE_DIR` | **Required** | The GCS path where the HBase snapshot export is located. | `gs://your-gcs-bucket/snapshots` |
| `NUM_SHARDS` | **Required** (except `--restore-only`) | The number of shards to split the import into for parallel processing. | `20` |
| `SERVICE_ACCOUNT` | *Optional* | The service account email to run the Dataflow jobs. | `[email protected]` |
| `MAX_INFLIGHT_RPCS` | *Optional* | Maximum number of inflight RPCs for Bigtable client. | `100` (Default) |
| `BULK_MUTATION_CLOSE_TIMEOUT_MINUTES` | *Optional* | Timeout in minutes for closing bulk mutations. | `30` (Default) |
| `NETWORK` | *Optional* | VPC Network name for Dataflow workers. | `your-network` |
| `SUBNETWORK` | *Optional* | VPC Subnetwork name for Dataflow workers. | `regions/us-central1/subnetworks/your-subnetwork` |
| `JOB_NAME_PREFIX` | *Optional* | Safe, unique prefix for all Dataflow jobs to prevent name collisions. | `import-<sanitized_table_name>` (Default) |
| `WORKER_MACHINE_TYPE` | *Optional* | Compute Engine machine type for Dataflow workers. | `n1-highmem-4` (Default) |
| `DISK_SIZE_GB` | *Optional* | Worker disk size in Gigabytes. | `500` (Default) |
| `MAX_NUM_WORKERS` | *Optional* | Maximum number of active Dataflow workers per job. | `10` (Default) |
| `USE_PUBLIC_IPS` | *Optional* | Whether Dataflow workers should have public IPs. | `false` (Default) |
| `ENABLE_SNAPPY` | *Optional* | Whether to enable Snappy compression for transit files. | `true` (Default) |

## Understanding Sharding

An HBase snapshot consists of multiple physical **regions** (ordered chunks of table keys). To migrate extremely large tables efficiently, you can partition (shard) the regions across multiple independent Dataflow jobs.

* **How Sharding Works:** The import tool distributes regions uniformly across a total number of shards (`NUM_SHARDS`) by hashing each region's encoded name and taking it modulo `NUM_SHARDS`.
* **Targeted Shards:** A Dataflow job configured with a specific `shardIndex` only reads and imports the HBase regions assigned to that particular shard.
* **Why use Sharding:** Instead of running a single massive Dataflow job that might hit quota limits or VM memory constraints, you can split the import into multiple smaller, parallelizable jobs.

## Usage

### Run a specific shard range

Runs a range of shard indices sequentially within the script execution.

> [!NOTE]
> Both `<start_shard>` and `<end_shard>` are **inclusive**. E.g., running `bin/run-snapshot-import.sh 0 5` will submit and execute Dataflow jobs for shards `0, 1, 2, 3, 4, and 5` sequentially.
> Shard indices must be non-negative integers strictly less than `NUM_SHARDS` (i.e. in the range `[0, NUM_SHARDS)`). The script validates this range and will fail fast if violated.

```bash
bin/run-snapshot-import.sh <start_shard> <end_shard>
```
Example: `bin/run-snapshot-import.sh 0 5`

### Run all shards (Auto-parallel mode)
```bash
bin/run-snapshot-import.sh --all
```
This mode will first run the blocking restore step, and then partition the total shards evenly and launch exactly 4 parallel runner streams in the background to process them. This ensures that no more than 4 Dataflow jobs are ever running concurrently, protecting your Bigtable instance from write-throttling and staying safely within GCP resource quotas.

## Advanced Usage

### Manual Parallel Execution

To run shards in parallel groups (e.g., assuming 20 shards total), you can run multiple instances of this script.

> [!IMPORTANT]
> Because concurrent shards cannot delete or overwrite the restored snapshot directory simultaneously, **no shard** performs the restore step during a sharded run. You MUST run the restore step explicitly first!

Example for manual parallel execution:
```bash
# 1. Run the blocking restore step first!
bin/run-snapshot-import.sh --restore-only

# 2. Once the restore is complete, launch shards in parallel:
bin/run-snapshot-import.sh 0 3 &
bin/run-snapshot-import.sh 4 7 &
bin/run-snapshot-import.sh 8 11 &
bin/run-snapshot-import.sh 12 15 &
bin/run-snapshot-import.sh 16 19 &
```

## Troubleshooting

### JDK Compatibility

If you are running on a newer, unsupported JDK version (e.g. JDK 25+) and hit ByteBuddy errors, you can simply set the `JVM_OPTS` variable to `"-Dnet.bytebuddy.experimental=true"` in the Configurations section of the `bin/run-snapshot-import.sh` script.
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
#!/bin/bash
Comment thread
mutianf marked this conversation as resolved.

# ==============================================================================
# HBase Snapshot Import Helper Script
# ==============================================================================
# This script runs a range of Dataflow snapshot import jobs sequentially or in parallel.
# Can be run from any directory, e.g., 'bin/run-snapshot-import.sh'.
#
# For detailed usage and advanced options, see: SNAPSHOT_IMPORT_USAGE.md
# ==============================================================================

# ------------------------------------------------------------------------------
# Environment Variables
# ------------------------------------------------------------------------------
# Most users will need to set these variables before running the script.
# See SNAPSHOT_IMPORT_USAGE.md for details and expected values.

# --- Required / Common Configurations ---
# export PROJECT_ID="your-project-id"
# export INSTANCE_ID="your-instance-id"
# export BUCKET="your-gcs-bucket"
# export REGION="us-central1"
#
# export TABLE_NAME="your-table-name"
# export SNAPSHOT_NAME="your-snapshot-name"
# export SNAPSHOT_SOURCE_DIR="gs://your-gcs-bucket/snapshots"
# export SERVICE_ACCOUNT="your-service-account"

# --- Sharding & Tuning ---
# A 'shard' is a partition of HBase regions. Sharding allows splitting the import into
# multiple independent Dataflow jobs running in parallel to speed up the migration.
# export NUM_SHARDS="20"
# export MAX_INFLIGHT_RPCS="100"
# export BULK_MUTATION_CLOSE_TIMEOUT_MINUTES="30"

# --- Network Configurations ---
# export NETWORK="your-network"
# export SUBNETWORK="your-subnetwork"

# ------------------------------------------------------------------------------
# Usage
# ------------------------------------------------------------------------------
# Usage: bin/run-snapshot-import.sh <start_shard> <end_shard>
# (Both start and end shard indices are inclusive)
# Or: bin/run-snapshot-import.sh --all
# (Runs all shards in parallel groups of 4 by default)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This header comment is stale — it still describes the old "groups of 4" model, but the implementation (and SNAPSHOT_IMPORT_USAGE.md) now partition into exactly 4 sequential runner streams. The two aren't equivalent: "groups of 4" caps 4 jobs at a time repeatedly, whereas the current code splits shards into 4 fixed lanes. Please update this line to match the "4 parallel runner streams" model so a reader skimming the script doesn't get the wrong mental model.

#
# Examples:
# bin/run-snapshot-import.sh 0 3
# bin/run-snapshot-import.sh --all

# Validate and parse arguments
if [ "$1" != "--all" ] && [ "$1" != "--restore-only" ]; then
if [ -z "$1" ] || [ -z "$2" ]; then
echo "Usage: $0 <start_shard> <end_shard> [additional_args...]"
echo " (Both start and end shard indices are inclusive)"
echo " Or: $0 --all [additional_args...]"
echo " Or: $0 --restore-only [additional_args...]"
exit 1
fi
if ! [[ "$1" =~ ^[0-9]+$ ]] || ! [[ "$2" =~ ^[0-9]+$ ]]; then
echo "❌ Error: Shard indices must be non-negative integers."
exit 1
fi
if [ "$1" -gt "$2" ]; then
echo "❌ Error: start_shard ($1) cannot be greater than end_shard ($2)."
exit 1
fi
START_SHARD=$1
END_SHARD=$2
Comment thread
tianlei2 marked this conversation as resolved.
EXTRA_ARGS=("${@:3}")
else
EXTRA_ARGS=("${@:2}")
fi
Comment on lines +53 to +74

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The script currently parses shard indices without validating that they are valid non-negative integers or that start_shard is less than or equal to end_shard. If invalid arguments are passed, the subsequent loop for (( i=START_SHARD; i<=END_SHARD; i++ )) will fail with a bash syntax error. Adding validation prevents these runtime errors.

if [ "$1" != "--all" ] && [ "$1" != "--restore-only" ]; then
    if [ -z "$1" ] || [ -z "$2" ]; then
        echo "Usage: $0 <start_shard> <end_shard> [additional_args...]"
        echo "        (Both start and end shard indices are inclusive)"
        echo "   Or: $0 --all [additional_args...]"
        echo "   Or: $0 --restore-only [additional_args...]"
        exit 1
    fi
    if ! [[ "$1" =~ ^[0-9]+$ ]] || ! [[ "$2" =~ ^[0-9]+$ ]]; then
        echo "❌ Error: Shard indices must be non-negative integers."
        exit 1
    fi
    if [ "$1" -gt "$2" ]; then
        echo "❌ Error: start_shard ($1) cannot be greater than end_shard ($2)."
        exit 1
    fi
    START_SHARD=$1
    END_SHARD=$2
    EXTRA_ARGS=("${@:3}")
else
    EXTRA_ARGS=("${@:2}")
fi


# Validate and export required environment variables
REQUIRED_VARS=(PROJECT_ID INSTANCE_ID BUCKET REGION TABLE_NAME SNAPSHOT_NAME SNAPSHOT_SOURCE_DIR)
for var in "${REQUIRED_VARS[@]}"; do
if [ -z "${!var}" ]; then
echo "❌ Error: Environment variable $var is not set."
exit 1
fi
export "${var}"
done
Comment thread
tianlei2 marked this conversation as resolved.

if [ "$1" != "--restore-only" ]; then
if [ -z "${NUM_SHARDS}" ]; then
echo "❌ Error: Environment variable NUM_SHARDS is not set."
exit 1
fi
if ! [[ "${NUM_SHARDS}" =~ ^[0-9]+$ ]] || [ "${NUM_SHARDS}" -le 0 ]; then
echo "❌ Error: NUM_SHARDS must be a positive integer."
exit 1
fi
export NUM_SHARDS
Comment thread
tianlei2 marked this conversation as resolved.
if [ "$1" != "--all" ]; then
if [ "${START_SHARD}" -ge "${NUM_SHARDS}" ] || [ "${END_SHARD}" -ge "${NUM_SHARDS}" ]; then
echo "❌ Error: Shard indices (${START_SHARD}, ${END_SHARD}) must be less than NUM_SHARDS (${NUM_SHARDS})."
exit 1
fi
fi
fi
Comment thread
tianlei2 marked this conversation as resolved.

# Strip leading gs:// and trailing slashes from BUCKET for robust GCS path construction
BUCKET="${BUCKET#gs://}"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BUCKET is nicely sanitized (strips gs:// and trailing slash), but SNAPSHOT_SOURCE_DIR is passed straight through to --hbaseSnapshotSourceDir. The asymmetry means a trailing slash or inconsistent prefix on SNAPSHOT_SOURCE_DIR is handled differently from BUCKET. Minor usability wart — consider matching the treatment or adding a comment noting it's intentional.

BUCKET="${BUCKET%/}"

# Set default values for optional tuning parameters
MAX_INFLIGHT_RPCS="${MAX_INFLIGHT_RPCS:-100}"
BULK_MUTATION_CLOSE_TIMEOUT_MINUTES="${BULK_MUTATION_CLOSE_TIMEOUT_MINUTES:-30}"
Comment thread
tianlei2 marked this conversation as resolved.

# Configurable Dataflow execution parameters
WORKER_MACHINE_TYPE="${WORKER_MACHINE_TYPE:-n1-highmem-4}"
DISK_SIZE_GB="${DISK_SIZE_GB:-500}"
MAX_NUM_WORKERS="${MAX_NUM_WORKERS:-10}"
USE_PUBLIC_IPS="${USE_PUBLIC_IPS:-false}"
ENABLE_SNAPPY="${ENABLE_SNAPPY:-true}"

# Generate a safe, unique job name prefix to prevent collisions
SAFE_TABLE_NAME=$(echo "${TABLE_NAME}" | tr '[:upper:]' '[:lower:]' | tr '_' '-' | tr -cd '[:alnum:]-')
JOB_NAME_PREFIX="${JOB_NAME_PREFIX:-import-${SAFE_TABLE_NAME}}"

# Configurations
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)

# Detect the newest shaded JAR dynamically in the target directory
JAR_PATH=""
for jar in "${SCRIPT_DIR}"/../target/bigtable-beam-import-*-shaded.jar; do
if [ -f "$jar" ]; then
if [ -z "${JAR_PATH}" ] || [ "$jar" -nt "${JAR_PATH}" ]; then
JAR_PATH="$jar"
fi
fi
done

if [ -z "${JAR_PATH}" ]; then
echo "❌ Error: Shaded JAR not found in ${SCRIPT_DIR}/../target/"
echo " Please compile and package the project first by running:"
echo " mvn clean package -DskipTests"
exit 1
fi
RESTORE_DIR="gs://${BUCKET}/restore-${SNAPSHOT_NAME}"
Comment thread
tianlei2 marked this conversation as resolved.
# If running the launcher on a newer, unsupported JDK version (e.g. JDK 25+),
# you can set JVM_OPTS to "-Dnet.bytebuddy.experimental=true" to bypass
# ByteBuddy class generation crashes during pipeline construction.
JVM_OPTS="${JVM_OPTS:-}"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

${JVM_OPTS} is the one intentional unquoted expansion in an otherwise carefully quoted script (it relies on word-splitting to pass multiple flags, which is correct). But shellcheck will flag this as SC2086, and there's no # shellcheck disable pragma in the file — if CI runs shellcheck, these three lines will fail it. Suggest adding a targeted # shellcheck disable=SC2086 directly above each java invocation to document the intent and keep CI green.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if we have this shellcheck tool, but good find by AI if it's there.


# Construct optional network arguments
NETWORK_ARGS=()
if [ -n "${NETWORK}" ]; then
NETWORK_ARGS+=("--network=${NETWORK}")
fi
if [ -n "${SUBNETWORK}" ]; then
NETWORK_ARGS+=("--subnetwork=${SUBNETWORK}")
fi

# Construct optional service account arguments
SERVICE_ACCOUNT_ARGS=()
if [ -n "${SERVICE_ACCOUNT}" ]; then
SERVICE_ACCOUNT_ARGS+=("--serviceAccount=${SERVICE_ACCOUNT}")
fi


# --- RESTORE ONLY MODE ---
if [ "$1" == "--restore-only" ]; then
echo "🚀 Performing snapshot restore (blocking)..."
if ! java ${JVM_OPTS} -jar "${JAR_PATH}" importsnapshot \
--runner=DataflowRunner \
--project="${PROJECT_ID}" \
--bigtableInstanceId="${INSTANCE_ID}" \
--bigtableTableId="${TABLE_NAME}" \
--hbaseSnapshotSourceDir="${SNAPSHOT_SOURCE_DIR}" \
--snapshots="${SNAPSHOT_NAME}:${TABLE_NAME}" \
--stagingLocation="gs://${BUCKET}/dataflow/staging" \
--tempLocation="gs://${BUCKET}/dataflow/temp" \
--region="${REGION}" \
--performOnlyRestoreStep=true \
--restorePath="${RESTORE_DIR}" \
--jobName="${JOB_NAME_PREFIX}-restore" \
"${SERVICE_ACCOUNT_ARGS[@]}" \
"${NETWORK_ARGS[@]}" \
"${EXTRA_ARGS[@]}"; then
echo "❌ Error: Snapshot restore failed."
exit 1
fi
echo "✅ Restore completed."
Comment thread
mutianf marked this conversation as resolved.
echo "⚠️ IMPORTANT: Please manually cleanup the restore path once validation succeeds:"
echo " gsutil rm -r \"${RESTORE_DIR}\""
exit 0
Comment thread
tianlei2 marked this conversation as resolved.
fi

# --- AUTO-PARALLEL MODE ---
if [ "$1" == "--all" ]; then
echo "🚀 Starting fully automated snapshot import..."

# Step 1: Perform ONLY the restore step
echo "Step 1/2: Performing snapshot restore (blocking)..."
if ! java ${JVM_OPTS} -jar "${JAR_PATH}" importsnapshot \
--runner=DataflowRunner \
--project="${PROJECT_ID}" \
--bigtableInstanceId="${INSTANCE_ID}" \
--bigtableTableId="${TABLE_NAME}" \
--hbaseSnapshotSourceDir="${SNAPSHOT_SOURCE_DIR}" \
--snapshots="${SNAPSHOT_NAME}:${TABLE_NAME}" \
--stagingLocation="gs://${BUCKET}/dataflow/staging" \
--tempLocation="gs://${BUCKET}/dataflow/temp" \
--region="${REGION}" \
--performOnlyRestoreStep=true \
--restorePath="${RESTORE_DIR}" \
--jobName="${JOB_NAME_PREFIX}-restore" \
"${SERVICE_ACCOUNT_ARGS[@]}" \
"${NETWORK_ARGS[@]}" \
"${EXTRA_ARGS[@]}"; then
echo "❌ Error: Snapshot restore failed. Aborting import."
exit 1
fi

echo "Restore completed. Proceeding to data import."

# Step 2: Launch 4 parallel runner streams
echo "Step 2/2: Launching 4 parallel runner streams..."
MAX_CONCURRENCY=4
SHARDS_PER_RUNNER=$(( (NUM_SHARDS + MAX_CONCURRENCY - 1) / MAX_CONCURRENCY ))

pids=()

This comment was marked as resolved.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nice-to-fix] The "Terminating background runners" message overpromises. Killing the runner subshells won't reap already-submitted Dataflow jobs — those keep running server-side and can't be cancelled with a local SIGTERM. Consider softening the wording to make clear that any Dataflow jobs already launched will continue and may need manual cancellation via gcloud dataflow jobs cancel. Otherwise an operator may Ctrl-C and wrongly assume everything stopped.

trap 'echo "⚠️ Interrupted. Terminating background runners..."; [ ${#pids[@]} -gt 0 ] && kill "${pids[@]}" 2>/dev/null; exit 1' INT TERM
for (( runner=0; runner<MAX_CONCURRENCY; runner++ )); do
start=$(( runner * SHARDS_PER_RUNNER ))
end=$(( start + SHARDS_PER_RUNNER - 1 ))
[ $start -ge $NUM_SHARDS ] && break
[ $end -ge $NUM_SHARDS ] && end=$((NUM_SHARDS - 1))

echo "Launching runner $runner: shards $start to $end in background"
# Call ourselves with the range and propagate any extra arguments!
bash "${SCRIPT_DIR}/$(basename "${BASH_SOURCE[0]}")" "$start" "$end" "${EXTRA_ARGS[@]}" &
Comment thread
tianlei2 marked this conversation as resolved.
pids+=($!)
done

echo "All groups launched. Waiting for all background jobs to finish..."
failed=0
for pid in "${pids[@]}"; do
if ! wait "$pid"; then
failed=1
fi
done

if [ $failed -ne 0 ]; then
echo "❌ Error: One or more background import jobs failed."
exit 1
fi

echo "🎉 All import jobs completed!"
echo "⚠️ IMPORTANT: Please manually cleanup the restore path once validation succeeds:"
echo " gsutil rm -r \"${RESTORE_DIR}\""
exit 0
fi
Comment thread
tianlei2 marked this conversation as resolved.
# ----------------------------------------

# Standard Range Mode
for (( i=START_SHARD; i<=END_SHARD; i++ )); do
echo "Submitting Dataflow job for shardIndex: $i"

# As per the sharding contract, ALL parallel sharded jobs MUST skip the restore step
# to prevent concurrent shards from deleting the restore path.
# The --all mode runs performOnlyRestoreStep=true automatically in Step 1.
SKIP_RESTORE="true"

JOB="${JOB_NAME_PREFIX}-${i}"
if ! java ${JVM_OPTS} -jar "${JAR_PATH}" importsnapshot \
--runner=DataflowRunner \
--project="${PROJECT_ID}" \
--bigtableInstanceId="${INSTANCE_ID}" \
--bigtableTableId="${TABLE_NAME}" \
--hbaseSnapshotSourceDir="${SNAPSHOT_SOURCE_DIR}" \
--snapshots="${SNAPSHOT_NAME}:${TABLE_NAME}" \
--stagingLocation="gs://${BUCKET}/dataflow/staging" \
--tempLocation="gs://${BUCKET}/dataflow/temp" \
--workerMachineType="${WORKER_MACHINE_TYPE}" \
--diskSizeGb="${DISK_SIZE_GB}" \
--maxNumWorkers="${MAX_NUM_WORKERS}" \
--region="${REGION}" \
"${SERVICE_ACCOUNT_ARGS[@]}" \
--usePublicIps="${USE_PUBLIC_IPS}" \
--enableSnappy="${ENABLE_SNAPPY}" \
--skipRestoreStep="${SKIP_RESTORE}" \
--deleteRestoredSnapshots=false \
--restorePath="${RESTORE_DIR}" \
--numShards="${NUM_SHARDS}" \
--shardIndex="${i}" \
--jobName="${JOB}" \
"${NETWORK_ARGS[@]}" \
--maxInflightRpcs="${MAX_INFLIGHT_RPCS}" \
--bulkMutationCloseTimeoutMinutes="${BULK_MUTATION_CLOSE_TIMEOUT_MINUTES}" \
"${EXTRA_ARGS[@]}"; then
echo "❌ Error: Dataflow job submission failed for shardIndex: ${i}"
exit 1
fi

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[should-decide] Both --restore-only and --all print the manual gsutil rm -r "${RESTORE_DIR}" cleanup reminder, but plain range mode does not. Anyone following the manual parallel-execution workflow in the docs (run-restore-only, then several range invocations) finishes their last batch with no cleanup reminder at all. Either print the same notice after this loop, or explicitly document that the reminder only appears in --all/--restore-only. Flagging so it's a conscious choice rather than an accidental gap.

# Sequential within this script instance
done
1 change: 0 additions & 1 deletion bigtable-dataflow-parent/bigtable-beam-import/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,6 @@ limitations under the License.
<exclude>META-INF/*.RSA</exclude>
<exclude>META-INF/**/pom.properties</exclude>
<exclude>META-INF/**/pom.xml</exclude>
<exclude>META-INF/MANIFEST.MF</exclude>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the MANIFEST.MF exclusion preserves the Multi-Release: true header required to load JDK 21-compatible dependency classes and prevent startup crashes, while remaining fully backward-compatible and safe for JDK 8.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[optional — verify] The rationale for un-excluding MANIFEST.MF (preserving Multi-Release: true for JDK 21 class loading) is sound. One sanity check before merge: since the shade plugin will now merge manifests, confirm the shaded jar doesn't inherit an unexpected Main-Class or stale entries from a dependency — a quick unzip -p target/*-shaded.jar META-INF/MANIFEST.MF should confirm it's clean.

<exclude>META-INF/LICENSE</exclude>
<exclude>META-INF/NOTICE.txt</exclude>
<exclude>META-INF/NOTICE</exclude>
Expand Down
Loading