Migrate Existing kdb+ Data (Initial Import)¶
This page explains how to migrate an existing kdb+ historical database (HDB) into the KDB-X DB Service using the initial import process.
Batch ingest vs initial import
Use initial import when migrating a partitioned kdb+ HDB. Use batch ingest (via the file import API or kdb database API) for ongoing backfills and scheduled loads. Initial import uses symbolic links to avoid copying data, making it much faster than re-ingesting through the API for large datasets.
Prerequisites¶
The kubectl commands on this page assume $NAMESPACE is set to the namespace you are deploying into, as in the quickstart.
Before starting an initial import:
- Clustered only. Initial import is a feature of the clustered DB Service. For single-node, use the kdb database import API instead.
- Back up your data. The import process modifies the sym file and partition structure. Take a full backup before proceeding.
- Schema compatibility. Table schemas in the source HDB must be compatible with the target DB Service table definitions. Use the
create-schema.qscript (see Step 2) to generate a compatible assembly YAML schema from your existing HDB. - Partitioned, splayed, and basic tables are supported. Data in object storage is not transformed and stays in standard kdb+ format.
Process overview¶
Initial import stages your existing HDB on a persistent volume, then has the storage manager (SM) register it in place on first startup rather than re-ingesting it. The steps that follow work through that process in order:
- Create and configure a Kubernetes PVC to hold the HDB data
- Generate an assembly schema from your existing HDB using
create-schema.q - Create a copy pod, and copy the sym file and partitions to the PVC
- Configure the assembly YAML with
initialImport: true - Deploy with Helm — SM detects and registers the staged data on startup
- Verify the migrated data is queryable
Step 1: Create the PVC¶
Create a Kubernetes PVC to hold the HDB data. The PVC must be created before deploying the DB Service so the SM can mount it on startup.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-db-hdb # must be <assembly-name>-hdb
spec:
storageClassName: standard # adjust to your cluster's storage class
accessModes:
- ReadWriteMany
resources:
requests:
storage: 100Gi
kubectl apply -f hdb-pvc.yaml --namespace "$NAMESPACE"
Check available storage classes on your cluster:
kubectl get storageclass
Step 2: Generate a schema¶
The create-schema.q script reads an existing kdb+ HDB and generates a compatible assembly YAML schema section. Copy the script from Insights schema creation into a file called create-schema.q, then run it against your source HDB:
q create-schema.q -db /path/to/source-hdb -out schema.yaml -fmt yaml
Options:
| Option | Description |
|---|---|
-db <path> |
Path to the source kdb+ database. Defaults to the current directory. |
-out <path> |
Output path. Defaults to stdout. |
-fmt yaml |
Output format. Use yaml to generate the assembly schema section used by the DB Service. |
Review the output
The script cannot determine all configuration values automatically. Output contains @EDITME@ placeholders where values must be filled in manually. Review and edit the generated schema before using it in your assembly.
Step 3: Copy data to the PVC¶
Create a copy pod to mount the PVC and copy your source data into it.
Create the copy pod¶
apiVersion: v1
kind: Pod
metadata:
name: import-copy-pod
spec:
securityContext:
fsGroup: 2000
containers:
- name: copy-container
image: amazonlinux:2
stdin: true
command: ["/bin/bash", "-c"]
args:
- |
yum install -y rsync
mkdir -p /data/db/hdb/data/
while true; do sleep 30; done;
volumeMounts:
- mountPath: /data/db/hdb
name: hdb-storage
volumes:
- name: hdb-storage
persistentVolumeClaim:
claimName: my-db-hdb
kubectl apply -f copy-pod.yaml --namespace "$NAMESPACE"
kubectl get pod import-copy-pod --namespace "$NAMESPACE" # wait for Running
Copy the sym file¶
The sym file must be copied to the data/ subdirectory of the HDB mount root. This is the location SM expects:
kubectl cp sym import-copy-pod:/data/db/hdb/data/ --namespace "$NAMESPACE"
Copy partitions¶
For efficient transfer with retry logic, use krsync.sh — a wrapper script that uses rsync over kubectl exec. Create the file krsync.sh with the following content:
#!/bin/bash
if [ -z "$RSYNC_RUNNING" ]; then
if [ "$#" -ne 3 ]; then
echo "Usage: $0 <local_directory> <pod_name> <target_directory_in_pod>"
exit 1
fi
local_dir=$1
pod=$2
target_dir=$3
max_retries=5
retry_count=0
success=0
export RSYNC_RUNNING=true
while [ $retry_count -lt $max_retries ]; do
echo "Attempt $(($retry_count + 1)) of $max_retries..."
rsync -av --progress --stats -e "bash $0" "$local_dir" "$pod:$target_dir"
if [ $? -eq 0 ]; then
echo "Rsync successful on attempt $(($retry_count + 1))"
success=1
break
fi
retry_count=$(($retry_count + 1))
sleep 10
done
if [ $success -eq 0 ]; then
echo "Rsync failed after $max_retries attempts"
exit 1
fi
exit 0
fi
pod=$1
shift
kubectl exec -i $pod -- "$@"
chmod +x krsync.sh
# Copy each date partition
bash krsync.sh /path/to/source-hdb/2026.01.01 import-copy-pod /data/db/hdb/data/
bash krsync.sh /path/to/source-hdb/2026.01.02 import-copy-pod /data/db/hdb/data/
# Repeat for all partitions, or use a loop
For object storage, upload partitions directly to your bucket while preserving the directory structure (sym, 2026.01.01/tablename/, etc.).
Step 4: Configure the assembly¶
Add the generated schema to your assembly YAML. Set initialImport: true on the SM — this tells the SM to look for existing data in the HDB mount's data/ directory on startup:
name: my-db
labels:
region: amer
tables:
# Paste generated schema from Step 2 here
trade:
type: partitioned
prtnCol: realTime
sortColsDisk: [sym]
sortColsOrd: [sym]
columns:
- name: realTime
type: timestamp
- name: sym
type: symbol
attrDisk: parted
attrOrd: parted
- name: price
type: float
- name: size
type: long
bus:
stream:
protocol: rt
topic: stream
mounts:
rdb:
type: stream
partition: none
baseURI: none
idb:
type: local
partition: ordinal
baseURI: file:///data/db/idb
hdb:
type: local
partition: date
baseURI: file:///data/db/hdb
elements:
dap:
instances:
rdb:
mountName: rdb
idb:
mountName: idb
hdb:
mountName: hdb
sm:
source: stream
initialImport: true # tells SM to register existing data on startup
tiers:
- name: rdb
mount: rdb
- name: idb
mount: idb
schedule:
freq: 00:10:00
- name: hdb
mount: hdb
schedule:
freq: 1D00:00:00
snap: 01:35:00
Step 5: Deploy with Helm¶
Deploy by following the Clustered steps in Start the DB Service. The single-node steps in that section do not apply, as initial import is clustered-only. Two things differ for an initial import:
- Deploy with the assembly you configured in Step 4, including
initialImport: true, rather than an unmodified assembly from the reference architecture. - The namespace and the
<assembly-name>-hdbPVC already exist from Step 1, so the SM finds the staged data when it mounts the PVC on startup.
SM validates the staged data against the schema on startup. If validation fails, SM logs details and terminates. Resolve the reported issues and restart SM.
Remove initialImport after first startup
Once SM has successfully started and registered the data, remove initialImport: true from the assembly. It is redundant after the first run.
Step 6: Verify¶
Once all pods are running, confirm the historical data is accessible:
session:dbs.createSession["your-gateway-host:8080"]
session.querySimple[`table`startTS`endTS`limit!(`trade; 2026.01.01D; 2026.01.02D; 5)]
curl -X POST "http://your-gateway-host:8080/api/v0/query/simple" \
-H "Content-Type: application/json" \
-d '{"table": "trade", "startTS": "2026.01.01D", "endTS": "2026.01.02D", "limit": 5}'
Troubleshooting¶
SM terminates on startup.¶
Check SM logs for validation errors:
kubectl logs -l component=storage-manager --namespace "$NAMESPACE"
Common causes: sym file not in <baseURI>/data/, schema mismatch between assembly and source HDB, or missing partitions.
No data returned after deployment.¶
Confirm startTS/endTS cover the date range of the staged partitions and that the sym file was copied before the partition directories.
For additional troubleshooting, see Troubleshooting.