Verify: migrate from DigitalOcean to KiviDB

Compare the key counts on both sides. On a live source they move; after writes stop they must match:

Compare the key counts on both sides. On a live source they move; after writes stop they must match:

valkey-cli -u "$DO_URI" INFO keyspace
valkey-cli -u "$KIVIDB_URI" --cacert kividb-ca.pem INFO keyspace

Then spot-check random keys: the type, the value and the TTL. Save this as spot-check.sh:

#!/usr/bin/env bash
# Compare N random keys between the source and KiviDB: type, value and TTL.
N=${1:-1000}
CLI=${CLI:-redis-cli}
src() { $CLI $SRC --no-auth-warning --raw "$@"; }
dst() { $CLI $DST --no-auth-warning --raw "$@"; }

dump() { # $1 = src|dst, $2 = type, $3 = key: the value in a comparable form
  case $2 in
    string) $1 GET "$3" ;;
    list)   $1 LRANGE "$3" 0 -1 ;;
    set)    $1 SMEMBERS "$3" | sort ;;
    zset)   $1 ZRANGE "$3" 0 -1 WITHSCORES ;;
    hash)   $1 HGETALL "$3" | paste - - | sort ;;
    stream) $1 XRANGE "$3" - + ;;
    *)      echo "unknown type $2" ;;
  esac | sha256sum
}

bad=0
for ((i = 0; i < N; i++)); do
  key=$(src RANDOMKEY)
  [ -z "$key" ] && { echo "source is empty"; exit 1; }
  t=$(src TYPE "$key")
  if [ "$(dst TYPE "$key")" != "$t" ]; then
    echo "MISSING or wrong type: $key ($t)"; bad=$((bad + 1)); continue
  fi
  if [ "$(dump src "$t" "$key")" != "$(dump dst "$t" "$key")" ]; then
    echo "VALUE differs: $key ($t)"; bad=$((bad + 1)); continue
  fi
  s=$(src PTTL "$key"); d=$(dst PTTL "$key")
  if [ "$s" -lt 0 ] || [ "$d" -lt 0 ]; then
    [ "$s" = "$d" ] || { echo "TTL differs: $key source=$s target=$d"; bad=$((bad + 1)); }
  elif [ $((s > d ? s - d : d - s)) -gt 10000 ]; then
    echo "TTL differs by more than 10s: $key source=${s}ms target=${d}ms"; bad=$((bad + 1))
  fi
done
echo "checked $N keys, $bad differ"
[ "$bad" -eq 0 ]

Run it with the connection options for each side:

SRC="-u $DO_URI" \
DST="-u $KIVIDB_URI --cacert kividb-ca.pem" \
CLI=valkey-cli ./spot-check.sh 1000

It checks database 0; add -n 1 to both SRC and DST for database 1. Key names with spaces or newlines are not handled. A copy made with RIOT --struct reports streams whose entries have their fields in a different order as VALUE differs; compare those with XLEN and XINFO STREAM instead.