diff --git a/.github/workflows/build_and_push_docker_image.yml b/.github/workflows/build_and_push_docker_image.yml
index e401b2f418..892e21114b 100644
--- a/.github/workflows/build_and_push_docker_image.yml
+++ b/.github/workflows/build_and_push_docker_image.yml
@@ -69,7 +69,15 @@ jobs:
run: echo "{\"credsStore\":\"ecr-login\"}" > /kaniko/.docker/config.json
- name: Kaniko build
- run: /kaniko/executor --reproducible --snapshotMode=redo --skip-unused-stages --dockerfile ${{ inputs.dockerfile-path }} --cache=true --cache-repo 369495373322.dkr.ecr.eu-central-1.amazonaws.com/cache --destination 369495373322.dkr.ecr.eu-central-1.amazonaws.com/${{ inputs.image-name }}:${{ needs.tag.outputs.build-tools-tag }}-amd64
+ run: |
+ /kaniko/executor \
+ --reproducible \
+ --snapshotMode=redo \
+ --skip-unused-stages \
+ --dockerfile ${{ inputs.dockerfile-path }} \
+ --cache=true \
+ --cache-repo 369495373322.dkr.ecr.eu-central-1.amazonaws.com/cache \
+ --destination 369495373322.dkr.ecr.eu-central-1.amazonaws.com/${{ inputs.image-name }}:${{ needs.tag.outputs.build-tools-tag }}-amd64
kaniko-arm:
if: needs.check-if-build-tools-dockerfile-changed.outputs.docker_file_changed == 'true'
@@ -85,7 +93,15 @@ jobs:
run: echo "{\"credsStore\":\"ecr-login\"}" > /kaniko/.docker/config.json
- name: Kaniko build
- run: /kaniko/executor --reproducible --snapshotMode=redo --skip-unused-stages --dockerfile ${{ inputs.dockerfile-path }} --cache=true --cache-repo 369495373322.dkr.ecr.eu-central-1.amazonaws.com/cache --destination 369495373322.dkr.ecr.eu-central-1.amazonaws.com/${{ inputs.image-name }}:${{ needs.tag.outputs.build-tools-tag }}-arm64
+ run: |
+ /kaniko/executor \
+ --reproducible \
+ --snapshotMode=redo \
+ --skip-unused-stages \
+ --dockerfile ${{ inputs.dockerfile-path }} \
+ --cache=true \
+ --cache-repo 369495373322.dkr.ecr.eu-central-1.amazonaws.com/cache \
+ --destination 369495373322.dkr.ecr.eu-central-1.amazonaws.com/${{ inputs.image-name }}:${{ needs.tag.outputs.build-tools-tag }}-arm64
manifest:
if: needs.check-if-build-tools-dockerfile-changed.outputs.docker_file_changed == 'true'
@@ -99,7 +115,10 @@ jobs:
steps:
- name: Create manifest
- run: docker manifest create 369495373322.dkr.ecr.eu-central-1.amazonaws.com/${{ inputs.image-name }}:${{ needs.tag.outputs.build-tools-tag }} --amend 369495373322.dkr.ecr.eu-central-1.amazonaws.com/${{ inputs.image-name }}:${{ needs.tag.outputs.build-tools-tag }}-amd64 --amend 369495373322.dkr.ecr.eu-central-1.amazonaws.com/${{ inputs.image-name }}:${{ needs.tag.outputs.build-tools-tag }}-arm64
+ run: |
+ docker manifest create 369495373322.dkr.ecr.eu-central-1.amazonaws.com/${{ inputs.image-name }}:${{ needs.tag.outputs.build-tools-tag }} \
+ --amend 369495373322.dkr.ecr.eu-central-1.amazonaws.com/${{ inputs.image-name }}:${{ needs.tag.outputs.build-tools-tag }}-amd64 \
+ --amend 369495373322.dkr.ecr.eu-central-1.amazonaws.com/${{ inputs.image-name }}:${{ needs.tag.outputs.build-tools-tag }}-arm64
- name: Push manifest
run: docker manifest push 369495373322.dkr.ecr.eu-central-1.amazonaws.com/${{ inputs.image-name }}:${{ needs.tag.outputs.build-tools-tag }}
diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml
index 2b88f09b3d..147d5cae2d 100644
--- a/.github/workflows/build_and_test.yml
+++ b/.github/workflows/build_and_test.yml
@@ -21,6 +21,8 @@ env:
COPT: '-Werror'
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_DEV }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY_DEV }}
+ # A concurrency group that we use for e2e-tests runs, matches `concurrency.group` above with `github.repository` as a prefix
+ E2E_CONCURRENCY_GROUP: ${{ github.repository }}-${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
jobs:
check-permissions:
@@ -44,6 +46,20 @@ jobs:
exit 1
+ cancel-previous-e2e-tests:
+ needs: [ check-permissions ]
+ if: github.event_name == 'pull_request'
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Cancel previous e2e-tests runs for this PR
+ env:
+ GH_TOKEN: ${{ secrets.CI_ACCESS_TOKEN }}
+ run: |
+ gh workflow --repo neondatabase/cloud \
+ run cancel-previous-in-concurrency-group.yml \
+ --field concurrency_group="${{ env.E2E_CONCURRENCY_GROUP }}"
+
tag:
needs: [ check-permissions ]
runs-on: [ self-hosted, gen3, small ]
@@ -186,7 +202,11 @@ jobs:
runs-on: [ self-hosted, gen3, large ]
container:
image: 369495373322.dkr.ecr.eu-central-1.amazonaws.com/build-tools:${{ needs.build-buildtools-image.outputs.build-tools-tag }}
- options: --init
+ # Raise locked memory limit for tokio-epoll-uring.
+ # On 5.10 LTS kernels < 5.10.162 (and generally mainline kernels < 5.12),
+ # io_uring will account the memory of the CQ and SQ as locked.
+ # More details: https://github.com/neondatabase/neon/issues/6373#issuecomment-1905814391
+ options: --init --shm-size=512mb --ulimit memlock=67108864:67108864
strategy:
fail-fast: false
matrix:
@@ -340,8 +360,12 @@ jobs:
${cov_prefix} mold -run cargo build $CARGO_FLAGS $CARGO_FEATURES --bins --tests
- name: Run rust tests
+ env:
+ NEXTEST_RETRIES: 3
run: |
- ${cov_prefix} cargo nextest run $CARGO_FLAGS $CARGO_FEATURES
+ for io_engine in std-fs tokio-epoll-uring ; do
+ NEON_PAGESERVER_UNIT_TEST_VIRTUAL_FILE_IOENGINE=$io_engine ${cov_prefix} cargo nextest run $CARGO_FLAGS $CARGO_FEATURES
+ done
# Run separate tests for real S3
export ENABLE_REAL_S3_REMOTE_STORAGE=nonempty
@@ -419,8 +443,8 @@ jobs:
runs-on: [ self-hosted, gen3, large ]
container:
image: 369495373322.dkr.ecr.eu-central-1.amazonaws.com/build-tools:${{ needs.build-buildtools-image.outputs.build-tools-tag }}
- # Default shared memory is 64mb
- options: --init --shm-size=512mb
+ # for changed limits, see comments on `options:` earlier in this file
+ options: --init --shm-size=512mb --ulimit memlock=67108864:67108864
strategy:
fail-fast: false
matrix:
@@ -448,6 +472,7 @@ jobs:
TEST_RESULT_CONNSTR: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
CHECK_ONDISK_DATA_COMPATIBILITY: nonempty
BUILD_TAG: ${{ needs.tag.outputs.build-tag }}
+ PAGESERVER_VIRTUAL_FILE_IO_ENGINE: std-fs
- name: Merge and upload coverage data
if: matrix.build_type == 'debug' && matrix.pg_version == 'v14'
@@ -458,12 +483,13 @@ jobs:
runs-on: [ self-hosted, gen3, small ]
container:
image: 369495373322.dkr.ecr.eu-central-1.amazonaws.com/build-tools:${{ needs.build-buildtools-image.outputs.build-tools-tag }}
- # Default shared memory is 64mb
- options: --init --shm-size=512mb
+ # for changed limits, see comments on `options:` earlier in this file
+ options: --init --shm-size=512mb --ulimit memlock=67108864:67108864
if: github.ref_name == 'main' || contains(github.event.pull_request.labels.*.name, 'run-benchmarks')
strategy:
fail-fast: false
matrix:
+ # the amount of groups (N) should be reflected in `extra_params: --splits N ...`
pytest_split_group: [ 1, 2, 3, 4 ]
build_type: [ release ]
steps:
@@ -477,11 +503,12 @@ jobs:
test_selection: performance
run_in_parallel: false
save_perf_report: ${{ github.ref_name == 'main' }}
- extra_params: --splits ${{ strategy.job-total }} --group ${{ matrix.pytest_split_group }}
+ extra_params: --splits 4 --group ${{ matrix.pytest_split_group }}
env:
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
TEST_RESULT_CONNSTR: "${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}"
+ PAGESERVER_VIRTUAL_FILE_IO_ENGINE: std-fs
# XXX: no coverage data handling here, since benchmarks are run on release builds,
# while coverage is currently collected for the debug ones
@@ -695,7 +722,8 @@ jobs:
\"commit_hash\": \"$COMMIT_SHA\",
\"remote_repo\": \"${{ github.repository }}\",
\"storage_image_tag\": \"${{ needs.tag.outputs.build-tag }}\",
- \"compute_image_tag\": \"${{ needs.tag.outputs.build-tag }}\"
+ \"compute_image_tag\": \"${{ needs.tag.outputs.build-tag }}\",
+ \"concurrency_group\": \"${{ env.E2E_CONCURRENCY_GROUP }}\"
}
}"
diff --git a/.github/workflows/neon_extra_builds.yml b/.github/workflows/neon_extra_builds.yml
index c6c2b7386a..f8fb62d3f8 100644
--- a/.github/workflows/neon_extra_builds.yml
+++ b/.github/workflows/neon_extra_builds.yml
@@ -124,12 +124,12 @@ jobs:
# Hence keeping target/ (and general cache size) smaller
BUILD_TYPE: release
CARGO_FEATURES: --features testing
- CARGO_FLAGS: --locked --release
+ CARGO_FLAGS: --release
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_DEV }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY_DEV }}
container:
- image: 369495373322.dkr.ecr.eu-central-1.amazonaws.com/rust:pinned
+ image: 369495373322.dkr.ecr.eu-central-1.amazonaws.com/build-tools:pinned
options: --init
steps:
@@ -210,18 +210,20 @@ jobs:
- name: Run cargo build
run: |
- mold -run cargo build $CARGO_FLAGS $CARGO_FEATURES --bins --tests
+ mold -run cargo build --locked $CARGO_FLAGS $CARGO_FEATURES --bins --tests
- name: Run cargo test
+ env:
+ NEXTEST_RETRIES: 3
run: |
- cargo test $CARGO_FLAGS $CARGO_FEATURES
+ cargo nextest run $CARGO_FEATURES
# Run separate tests for real S3
export ENABLE_REAL_S3_REMOTE_STORAGE=nonempty
export REMOTE_STORAGE_S3_BUCKET=neon-github-ci-tests
export REMOTE_STORAGE_S3_REGION=eu-central-1
# Avoid `$CARGO_FEATURES` since there's no `testing` feature in the e2e tests now
- cargo test $CARGO_FLAGS --package remote_storage --test test_real_s3
+ cargo nextest run --package remote_storage --test test_real_s3
# Run separate tests for real Azure Blob Storage
# XXX: replace region with `eu-central-1`-like region
@@ -231,7 +233,7 @@ jobs:
export REMOTE_STORAGE_AZURE_CONTAINER="${{ vars.REMOTE_STORAGE_AZURE_CONTAINER }}"
export REMOTE_STORAGE_AZURE_REGION="${{ vars.REMOTE_STORAGE_AZURE_REGION }}"
# Avoid `$CARGO_FEATURES` since there's no `testing` feature in the e2e tests now
- cargo test $CARGO_FLAGS --package remote_storage --test test_real_azure
+ cargo nextest run --package remote_storage --test test_real_azure
check-codestyle-rust-arm:
timeout-minutes: 90
diff --git a/.github/workflows/update_build_tools_image.yml b/.github/workflows/update_build_tools_image.yml
index 88bab797b7..900724fc60 100644
--- a/.github/workflows/update_build_tools_image.yml
+++ b/.github/workflows/update_build_tools_image.yml
@@ -20,111 +20,51 @@ defaults:
run:
shell: bash -euo pipefail {0}
-env:
- AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_DEV }}
- AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY_DEV }}
-
permissions: {}
jobs:
tag-image:
runs-on: [ self-hosted, gen3, small ]
- container: golang:1.19-bullseye
env:
- IMAGE: 369495373322.dkr.ecr.eu-central-1.amazonaws.com/build-tools
- FROM_TAG: ${{ inputs.from-tag }}
- TO_TAG: ${{ inputs.to-tag }}
- outputs:
- next-digest-buildtools: ${{ steps.next-digest.outputs.next-digest-buildtools }}
- prev-digest-buildtools: ${{ steps.prev-digest.outputs.prev-digest-buildtools }}
-
- steps:
- - name: Install Crane & ECR helper
- run: |
- go install github.com/google/go-containerregistry/cmd/crane@a54d64203cffcbf94146e04069aae4a97f228ee2 # v0.16.1
- go install github.com/awslabs/amazon-ecr-credential-helper/ecr-login/cli/docker-credential-ecr-login@adf1bafd791ae7d4ff098108b1e91f36a4da5404 # v0.7.1
-
- - name: Configure ECR login
- run: |
- mkdir /github/home/.docker/
- echo "{\"credsStore\":\"ecr-login\"}" > /github/home/.docker/config.json
-
- - name: Get source image digest
- id: next-digest
- run: |
- NEXT_DIGEST=$(crane digest ${IMAGE}:${FROM_TAG} || true)
- if [ -z "${NEXT_DIGEST}" ]; then
- echo >&2 "Image ${IMAGE}:${FROM_TAG} does not exist"
- exit 1
- fi
-
- echo "Current ${IMAGE}@${FROM_TAG} image is ${IMAGE}@${NEXT_DIGEST}"
- echo "next-digest-buildtools=$NEXT_DIGEST" >> $GITHUB_OUTPUT
-
- - name: Get destination image digest (if already exists)
- id: prev-digest
- run: |
- PREV_DIGEST=$(crane digest ${IMAGE}:${TO_TAG} || true)
- if [ -z "${PREV_DIGEST}" ]; then
- echo >&2 "Image ${IMAGE}:${TO_TAG} does not exist (it's ok)"
- else
- echo >&2 "Current ${IMAGE}@${TO_TAG} image is ${IMAGE}@${PREV_DIGEST}"
-
- echo "prev-digest-buildtools=$PREV_DIGEST" >> $GITHUB_OUTPUT
- fi
-
- - name: Tag image
- run: |
- crane tag "${IMAGE}:${FROM_TAG}" "${TO_TAG}"
-
- rollback-tag-image:
- needs: tag-image
- if: ${{ !success() }}
-
- runs-on: [ self-hosted, gen3, small ]
- container: golang:1.19-bullseye
-
- env:
- IMAGE: 369495373322.dkr.ecr.eu-central-1.amazonaws.com/build-tools
+ ECR_IMAGE: 369495373322.dkr.ecr.eu-central-1.amazonaws.com/build-tools
+ DOCKER_HUB_IMAGE: docker.io/neondatabase/build-tools
FROM_TAG: ${{ inputs.from-tag }}
TO_TAG: ${{ inputs.to-tag }}
steps:
- - name: Install Crane & ECR helper
+ # Use custom DOCKER_CONFIG directory to avoid conflicts with default settings
+ # The default value is ~/.docker
+ - name: Set custom docker config directory
run: |
- go install github.com/google/go-containerregistry/cmd/crane@a54d64203cffcbf94146e04069aae4a97f228ee2 # v0.16.1
- go install github.com/awslabs/amazon-ecr-credential-helper/ecr-login/cli/docker-credential-ecr-login@adf1bafd791ae7d4ff098108b1e91f36a4da5404 # v0.7.1
+ mkdir -p .docker-custom
+ echo DOCKER_CONFIG=$(pwd)/.docker-custom >> $GITHUB_ENV
- - name: Configure ECR login
+ - uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.NEON_DOCKERHUB_USERNAME }}
+ password: ${{ secrets.NEON_DOCKERHUB_PASSWORD }}
+
+ - uses: docker/login-action@v2
+ with:
+ registry: 369495373322.dkr.ecr.eu-central-1.amazonaws.com
+ username: ${{ secrets.AWS_ACCESS_KEY_DEV }}
+ password: ${{ secrets.AWS_SECRET_KEY_DEV }}
+
+ - uses: actions/setup-go@v5
+ with:
+ go-version: '1.21'
+
+ - name: Install crane
run: |
- mkdir /github/home/.docker/
- echo "{\"credsStore\":\"ecr-login\"}" > /github/home/.docker/config.json
+ go install github.com/google/go-containerregistry/cmd/crane@a0658aa1d0cc7a7f1bcc4a3af9155335b6943f40 # v0.18.0
- - name: Restore previous tag if needed
+ - name: Copy images
run: |
- NEXT_DIGEST="${{ needs.tag-image.outputs.next-digest-buildtools }}"
- PREV_DIGEST="${{ needs.tag-image.outputs.prev-digest-buildtools }}"
+ crane copy "${ECR_IMAGE}:${FROM_TAG}" "${ECR_IMAGE}:${TO_TAG}"
+ crane copy "${ECR_IMAGE}:${FROM_TAG}" "${DOCKER_HUB_IMAGE}:${TO_TAG}"
- if [ -z "${NEXT_DIGEST}" ]; then
- echo >&2 "Image ${IMAGE}:${FROM_TAG} does not exist, nothing to rollback"
- exit 0
- fi
-
- if [ -z "${PREV_DIGEST}" ]; then
- # I guess we should delete the tag here/untag the image, but crane does not support it
- # - https://github.com/google/go-containerregistry/issues/999
-
- echo >&2 "Image ${IMAGE}:${TO_TAG} did not exist, but it was created by the job, no need to rollback"
-
- exit 0
- fi
-
- CURRENT_DIGEST=$(crane digest "${IMAGE}:${TO_TAG}")
- if [ "${CURRENT_DIGEST}" == "${NEXT_DIGEST}" ]; then
- crane tag "${IMAGE}@${PREV_DIGEST}" "${TO_TAG}"
-
- echo >&2 "Successfully restored ${TO_TAG} tag from ${IMAGE}@${CURRENT_DIGEST} to ${IMAGE}@${PREV_DIGEST}"
- else
- echo >&2 "Image ${IMAGE}:${TO_TAG}@${CURRENT_DIGEST} is not required to be restored"
- fi
+ - name: Remove custom docker config directory
+ if: always()
+ run: |
+ rm -rf .docker-custom
diff --git a/Cargo.lock b/Cargo.lock
index 952034a16b..f0bcfb762a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -10,9 +10,9 @@ checksum = "8b5ace29ee3216de37c0546865ad08edef58b0f9e76838ed8959a84a990e58c5"
[[package]]
name = "addr2line"
-version = "0.19.0"
+version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
+checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [
"gimli",
]
@@ -278,6 +278,7 @@ dependencies = [
"camino",
"clap",
"control_plane",
+ "diesel",
"futures",
"git-version",
"hyper",
@@ -840,15 +841,15 @@ dependencies = [
[[package]]
name = "backtrace"
-version = "0.3.67"
+version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
+checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
- "miniz_oxide 0.6.2",
+ "miniz_oxide",
"object",
"rustc-demangle",
]
@@ -1215,7 +1216,7 @@ dependencies = [
"flate2",
"futures",
"hyper",
- "nix 0.26.2",
+ "nix 0.27.1",
"notify",
"num_cpus",
"opentelemetry",
@@ -1327,11 +1328,13 @@ dependencies = [
"clap",
"comfy-table",
"compute_api",
+ "diesel",
+ "diesel_migrations",
"futures",
"git-version",
"hex",
"hyper",
- "nix 0.26.2",
+ "nix 0.27.1",
"once_cell",
"pageserver_api",
"pageserver_client",
@@ -1341,6 +1344,7 @@ dependencies = [
"regex",
"reqwest",
"safekeeper_api",
+ "scopeguard",
"serde",
"serde_json",
"serde_with",
@@ -1636,6 +1640,52 @@ dependencies = [
"rusticata-macros",
]
+[[package]]
+name = "diesel"
+version = "2.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62c6fcf842f17f8c78ecf7c81d75c5ce84436b41ee07e03f490fbb5f5a8731d8"
+dependencies = [
+ "bitflags 2.4.1",
+ "byteorder",
+ "diesel_derives",
+ "itoa",
+ "pq-sys",
+ "serde_json",
+]
+
+[[package]]
+name = "diesel_derives"
+version = "2.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef8337737574f55a468005a83499da720f20c65586241ffea339db9ecdfd2b44"
+dependencies = [
+ "diesel_table_macro_syntax",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.32",
+]
+
+[[package]]
+name = "diesel_migrations"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6036b3f0120c5961381b570ee20a02432d7e2d27ea60de9578799cf9156914ac"
+dependencies = [
+ "diesel",
+ "migrations_internals",
+ "migrations_macros",
+]
+
+[[package]]
+name = "diesel_table_macro_syntax"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5"
+dependencies = [
+ "syn 2.0.32",
+]
+
[[package]]
name = "digest"
version = "0.10.7"
@@ -1872,13 +1922,13 @@ dependencies = [
[[package]]
name = "filetime"
-version = "0.2.21"
+version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
+checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall 0.2.16",
+ "redox_syscall 0.3.5",
"windows-sys 0.48.0",
]
@@ -1895,7 +1945,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
dependencies = [
"crc32fast",
- "miniz_oxide 0.7.1",
+ "miniz_oxide",
]
[[package]]
@@ -2093,9 +2143,9 @@ dependencies = [
[[package]]
name = "gimli"
-version = "0.27.2"
+version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "git-version"
@@ -2562,6 +2612,16 @@ dependencies = [
"windows-sys 0.48.0",
]
+[[package]]
+name = "io-uring"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "460648e47a07a43110fbfa2e0b14afb2be920093c31e5dccc50e49568e099762"
+dependencies = [
+ "bitflags 1.3.2",
+ "libc",
+]
+
[[package]]
name = "ipnet"
version = "2.9.0"
@@ -2748,18 +2808,18 @@ checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "memoffset"
-version = "0.7.1"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
+checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
dependencies = [
"autocfg",
]
[[package]]
name = "memoffset"
-version = "0.8.0"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
+checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
@@ -2775,6 +2835,27 @@ dependencies = [
"workspace_hack",
]
+[[package]]
+name = "migrations_internals"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f23f71580015254b020e856feac3df5878c2c7a8812297edd6c0a485ac9dada"
+dependencies = [
+ "serde",
+ "toml",
+]
+
+[[package]]
+name = "migrations_macros"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cce3325ac70e67bbab5bd837a31cae01f1a6db64e0e744a33cb03a543469ef08"
+dependencies = [
+ "migrations_internals",
+ "proc-macro2",
+ "quote",
+]
+
[[package]]
name = "mime"
version = "0.3.17"
@@ -2797,15 +2878,6 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-[[package]]
-name = "miniz_oxide"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
-dependencies = [
- "adler",
-]
-
[[package]]
name = "miniz_oxide"
version = "0.7.1"
@@ -2865,16 +2937,14 @@ dependencies = [
[[package]]
name = "nix"
-version = "0.26.2"
+version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
+checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.4.1",
"cfg-if",
"libc",
- "memoffset 0.7.1",
- "pin-utils",
- "static_assertions",
+ "memoffset 0.9.0",
]
[[package]]
@@ -2889,20 +2959,21 @@ dependencies = [
[[package]]
name = "notify"
-version = "5.2.0"
+version = "6.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "729f63e1ca555a43fe3efa4f3efdf4801c479da85b432242a7b726f353c88486"
+checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.4.1",
"crossbeam-channel",
"filetime",
"fsevent-sys",
"inotify 0.9.6",
"kqueue",
"libc",
+ "log",
"mio",
"walkdir",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -3028,9 +3099,9 @@ dependencies = [
[[package]]
name = "object"
-version = "0.30.3"
+version = "0.32.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
+checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
dependencies = [
"memchr",
]
@@ -3102,9 +3173,9 @@ dependencies = [
[[package]]
name = "opentelemetry"
-version = "0.19.0"
+version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f4b8347cc26099d3aeee044065ecc3ae11469796b4d65d065a23a584ed92a6f"
+checksum = "9591d937bc0e6d2feb6f71a559540ab300ea49955229c347a517a28d27784c54"
dependencies = [
"opentelemetry_api",
"opentelemetry_sdk",
@@ -3112,9 +3183,9 @@ dependencies = [
[[package]]
name = "opentelemetry-http"
-version = "0.8.0"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a819b71d6530c4297b49b3cae2939ab3a8cc1b9f382826a1bc29dd0ca3864906"
+checksum = "c7594ec0e11d8e33faf03530a4c49af7064ebba81c1480e01be67d90b356508b"
dependencies = [
"async-trait",
"bytes",
@@ -3125,54 +3196,56 @@ dependencies = [
[[package]]
name = "opentelemetry-otlp"
-version = "0.12.0"
+version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8af72d59a4484654ea8eb183fea5ae4eb6a41d7ac3e3bae5f4d2a282a3a7d3ca"
+checksum = "7e5e5a5c4135864099f3faafbe939eb4d7f9b80ebf68a8448da961b32a7c1275"
dependencies = [
"async-trait",
- "futures",
- "futures-util",
+ "futures-core",
"http",
- "opentelemetry",
"opentelemetry-http",
"opentelemetry-proto",
+ "opentelemetry-semantic-conventions",
+ "opentelemetry_api",
+ "opentelemetry_sdk",
"prost",
"reqwest",
"thiserror",
+ "tokio",
+ "tonic",
]
[[package]]
name = "opentelemetry-proto"
-version = "0.2.0"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "045f8eea8c0fa19f7d48e7bc3128a39c2e5c533d5c61298c548dfefc1064474c"
+checksum = "b1e3f814aa9f8c905d0ee4bde026afd3b2577a97c10e1699912e3e44f0c4cbeb"
dependencies = [
- "futures",
- "futures-util",
- "opentelemetry",
+ "opentelemetry_api",
+ "opentelemetry_sdk",
"prost",
- "tonic 0.8.3",
+ "tonic",
]
[[package]]
name = "opentelemetry-semantic-conventions"
-version = "0.11.0"
+version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24e33428e6bf08c6f7fcea4ddb8e358fab0fe48ab877a87c70c6ebe20f673ce5"
+checksum = "73c9f9340ad135068800e7f1b24e9e09ed9e7143f5bf8518ded3d3ec69789269"
dependencies = [
"opentelemetry",
]
[[package]]
name = "opentelemetry_api"
-version = "0.19.0"
+version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed41783a5bf567688eb38372f2b7a8530f5a607a4b49d38dd7573236c23ca7e2"
+checksum = "8a81f725323db1b1206ca3da8bb19874bbd3f57c3bcd59471bfb04525b265b9b"
dependencies = [
- "fnv",
"futures-channel",
"futures-util",
"indexmap 1.9.3",
+ "js-sys",
"once_cell",
"pin-project-lite",
"thiserror",
@@ -3181,21 +3254,22 @@ dependencies = [
[[package]]
name = "opentelemetry_sdk"
-version = "0.19.0"
+version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1"
+checksum = "fa8e705a0612d48139799fcbaba0d4a90f06277153e43dd2bdc16c6f0edd8026"
dependencies = [
"async-trait",
"crossbeam-channel",
- "dashmap",
- "fnv",
"futures-channel",
"futures-executor",
"futures-util",
"once_cell",
"opentelemetry_api",
+ "ordered-float 3.9.2",
"percent-encoding",
"rand 0.8.5",
+ "regex",
+ "serde_json",
"thiserror",
"tokio",
"tokio-stream",
@@ -3210,6 +3284,15 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "ordered-float"
+version = "3.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc"
+dependencies = [
+ "num-traits",
+]
+
[[package]]
name = "ordered-multimap"
version = "0.7.1"
@@ -3325,7 +3408,7 @@ dependencies = [
"itertools",
"md5",
"metrics",
- "nix 0.26.2",
+ "nix 0.27.1",
"num-traits",
"num_cpus",
"once_cell",
@@ -3358,6 +3441,7 @@ dependencies = [
"tenant_size_model",
"thiserror",
"tokio",
+ "tokio-epoll-uring",
"tokio-io-timeout",
"tokio-postgres",
"tokio-stream",
@@ -3780,6 +3864,15 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+[[package]]
+name = "pq-sys"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31c0052426df997c0cbd30789eb44ca097e3541717a7b8fa36b1c464ee7edebd"
+dependencies = [
+ "vcpkg",
+]
+
[[package]]
name = "pq_proto"
version = "0.1.0"
@@ -4339,9 +4432,9 @@ dependencies = [
[[package]]
name = "reqwest-tracing"
-version = "0.4.5"
+version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b97ad83c2fc18113346b7158d79732242002427c30f620fa817c1f32901e0a8"
+checksum = "5a0152176687dd5cfe7f507ac1cb1a491c679cfe483afd133a7db7aaea818bb3"
dependencies = [
"anyhow",
"async-trait",
@@ -5110,9 +5203,9 @@ checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
[[package]]
name = "smol_str"
-version = "0.2.0"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c"
+checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49"
dependencies = [
"serde",
]
@@ -5195,7 +5288,7 @@ dependencies = [
"prost",
"tokio",
"tokio-stream",
- "tonic 0.9.2",
+ "tonic",
"tonic-build",
"tracing",
"utils",
@@ -5379,18 +5472,18 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "1.0.40"
+version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
+checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.40"
+version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
+checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
dependencies = [
"proc-macro2",
"quote",
@@ -5415,7 +5508,7 @@ checksum = "7e54bc85fc7faa8bc175c4bab5b92ba8d9a3ce893d0e9f42cc455c8ab16a9e09"
dependencies = [
"byteorder",
"integer-encoding",
- "ordered-float",
+ "ordered-float 2.10.1",
]
[[package]]
@@ -5514,6 +5607,21 @@ dependencies = [
"windows-sys 0.48.0",
]
+[[package]]
+name = "tokio-epoll-uring"
+version = "0.1.0"
+source = "git+https://github.com/neondatabase/tokio-epoll-uring.git?branch=main#0dd3a2f8bf3239d34a19719ef1a74146c093126f"
+dependencies = [
+ "futures",
+ "once_cell",
+ "scopeguard",
+ "thiserror",
+ "tokio",
+ "tokio-util",
+ "tracing",
+ "uring-common",
+]
+
[[package]]
name = "tokio-io-timeout"
version = "1.2.0"
@@ -5681,38 +5789,6 @@ dependencies = [
"winnow",
]
-[[package]]
-name = "tonic"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb"
-dependencies = [
- "async-stream",
- "async-trait",
- "axum",
- "base64 0.13.1",
- "bytes",
- "futures-core",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "hyper",
- "hyper-timeout",
- "percent-encoding",
- "pin-project",
- "prost",
- "prost-derive",
- "tokio",
- "tokio-stream",
- "tokio-util",
- "tower",
- "tower-layer",
- "tower-service",
- "tracing",
- "tracing-futures",
-]
-
[[package]]
name = "tonic"
version = "0.9.2"
@@ -5856,16 +5932,6 @@ dependencies = [
"tracing-subscriber",
]
-[[package]]
-name = "tracing-futures"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
-dependencies = [
- "pin-project",
- "tracing",
-]
-
[[package]]
name = "tracing-log"
version = "0.1.3"
@@ -5879,9 +5945,9 @@ dependencies = [
[[package]]
name = "tracing-opentelemetry"
-version = "0.19.0"
+version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00a39dcf9bfc1742fa4d6215253b33a6e474be78275884c216fc2a06267b3600"
+checksum = "fc09e402904a5261e42cf27aea09ccb7d5318c6717a9eec3d8e2e65c56b18f19"
dependencies = [
"once_cell",
"opentelemetry",
@@ -6065,6 +6131,15 @@ dependencies = [
"webpki-roots 0.23.1",
]
+[[package]]
+name = "uring-common"
+version = "0.1.0"
+source = "git+https://github.com/neondatabase/tokio-epoll-uring.git?branch=main#0dd3a2f8bf3239d34a19719ef1a74146c093126f"
+dependencies = [
+ "io-uring",
+ "libc",
+]
+
[[package]]
name = "url"
version = "2.3.1"
@@ -6118,7 +6193,7 @@ dependencies = [
"hyper",
"jsonwebtoken",
"metrics",
- "nix 0.26.2",
+ "nix 0.27.1",
"once_cell",
"pin-project-lite",
"postgres_connection",
@@ -6626,10 +6701,9 @@ dependencies = [
"clap",
"clap_builder",
"crossbeam-utils",
- "dashmap",
+ "diesel",
"either",
"fail",
- "futures",
"futures-channel",
"futures-core",
"futures-executor",
@@ -6674,6 +6748,7 @@ dependencies = [
"tokio-util",
"toml_datetime",
"toml_edit",
+ "tonic",
"tower",
"tracing",
"tracing-core",
diff --git a/Cargo.toml b/Cargo.toml
index 5d5d2f4a55..8afab02b15 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -99,14 +99,14 @@ libc = "0.2"
md5 = "0.7.0"
memoffset = "0.8"
native-tls = "0.2"
-nix = "0.26"
-notify = "5.0.0"
+nix = { version = "0.27", features = ["fs", "process", "socket", "signal", "poll"] }
+notify = "6.0.0"
num_cpus = "1.15"
num-traits = "0.2.15"
once_cell = "1.13"
-opentelemetry = "0.19.0"
-opentelemetry-otlp = { version = "0.12.0", default_features=false, features = ["http-proto", "trace", "http", "reqwest-client"] }
-opentelemetry-semantic-conventions = "0.11.0"
+opentelemetry = "0.20.0"
+opentelemetry-otlp = { version = "0.13.0", default_features=false, features = ["http-proto", "trace", "http", "reqwest-client"] }
+opentelemetry-semantic-conventions = "0.12.0"
parking_lot = "0.12"
parquet = { version = "49.0.0", default-features = false, features = ["zstd"] }
parquet_derive = "49.0.0"
@@ -118,7 +118,7 @@ rand = "0.8"
redis = { version = "0.24.0", features = ["tokio-rustls-comp", "keep-alive"] }
regex = "1.10.2"
reqwest = { version = "0.11", default-features = false, features = ["rustls-tls"] }
-reqwest-tracing = { version = "0.4.0", features = ["opentelemetry_0_19"] }
+reqwest-tracing = { version = "0.4.7", features = ["opentelemetry_0_20"] }
reqwest-middleware = "0.2.0"
reqwest-retry = "0.2.2"
routerify = "3"
@@ -151,6 +151,7 @@ test-context = "0.1"
thiserror = "1.0"
tls-listener = { version = "0.7", features = ["rustls", "hyper-h1"] }
tokio = { version = "1.17", features = ["macros"] }
+tokio-epoll-uring = { git = "https://github.com/neondatabase/tokio-epoll-uring.git" , branch = "main" }
tokio-io-timeout = "1.2.0"
tokio-postgres-rustls = "0.10.0"
tokio-rustls = "0.24"
@@ -162,7 +163,7 @@ toml_edit = "0.19"
tonic = {version = "0.9", features = ["tls", "tls-roots"]}
tracing = "0.1"
tracing-error = "0.2.0"
-tracing-opentelemetry = "0.19.0"
+tracing-opentelemetry = "0.20.0"
tracing-subscriber = { version = "0.3", default_features = false, features = ["smallvec", "fmt", "tracing-log", "std", "env-filter", "json"] }
url = "2.2"
uuid = { version = "1.6.1", features = ["v4", "v7", "serde"] }
diff --git a/Dockerfile.compute-node b/Dockerfile.compute-node
index 908460018f..299c4097e8 100644
--- a/Dockerfile.compute-node
+++ b/Dockerfile.compute-node
@@ -52,7 +52,7 @@ RUN cd postgres && \
# We need to grant EXECUTE on pg_stat_statements_reset() to neon_superuser.
# In vanilla postgres this function is limited to Postgres role superuser.
# In neon we have neon_superuser role that is not a superuser but replaces superuser in some cases.
- # We could add the additional grant statements to the postgres repository but it would be hard to maintain,
+ # We could add the additional grant statements to the postgres repository but it would be hard to maintain,
# whenever we need to pick up a new postgres version and we want to limit the changes in our postgres fork,
# so we do it here.
old_list="pg_stat_statements--1.0--1.1.sql pg_stat_statements--1.1--1.2.sql pg_stat_statements--1.2--1.3.sql pg_stat_statements--1.3--1.4.sql pg_stat_statements--1.4--1.5.sql pg_stat_statements--1.4.sql pg_stat_statements--1.5--1.6.sql"; \
@@ -63,14 +63,14 @@ RUN cd postgres && \
echo 'GRANT EXECUTE ON FUNCTION pg_stat_statements_reset() TO neon_superuser;' >> $file; \
fi; \
done; \
- # the second loop is for pg_stat_statement extension versions >= 1.7,
+ # the second loop is for pg_stat_statement extension versions >= 1.7,
# where pg_stat_statement_reset() got 3 additional arguments
for file in /usr/local/pgsql/share/extension/pg_stat_statements--*.sql; do \
filename=$(basename "$file"); \
if ! echo "$old_list" | grep -q -F "$filename"; then \
echo 'GRANT EXECUTE ON FUNCTION pg_stat_statements_reset(Oid, Oid, bigint) TO neon_superuser;' >> $file; \
fi; \
- done
+ done
#########################################################################################
#
@@ -143,29 +143,24 @@ RUN wget https://github.com/pgRouting/pgrouting/archive/v3.4.2.tar.gz -O pgrouti
#########################################################################################
FROM build-deps AS plv8-build
COPY --from=pg-build /usr/local/pgsql/ /usr/local/pgsql/
+
RUN apt update && \
apt install -y ninja-build python3-dev libncurses5 binutils clang
-RUN case "${PG_VERSION}" in \
- "v14" | "v15") \
- export PLV8_VERSION=3.1.5 \
- export PLV8_CHECKSUM=1e108d5df639e4c189e1c5bdfa2432a521c126ca89e7e5a969d46899ca7bf106 \
- ;; \
- "v16") \
- export PLV8_VERSION=3.1.8 \
- export PLV8_CHECKSUM=92b10c7db39afdae97ff748c9ec54713826af222c459084ad002571b79eb3f49 \
- ;; \
- *) \
- echo "Export the valid PG_VERSION variable" && exit 1 \
- ;; \
- esac && \
- wget https://github.com/plv8/plv8/archive/refs/tags/v${PLV8_VERSION}.tar.gz -O plv8.tar.gz && \
- echo "${PLV8_CHECKSUM} plv8.tar.gz" | sha256sum --check && \
+RUN wget https://github.com/plv8/plv8/archive/refs/tags/v3.1.10.tar.gz -O plv8.tar.gz && \
+ echo "7096c3290928561f0d4901b7a52794295dc47f6303102fae3f8e42dd575ad97d plv8.tar.gz" | sha256sum --check && \
mkdir plv8-src && cd plv8-src && tar xvzf ../plv8.tar.gz --strip-components=1 -C . && \
+ # generate and copy upgrade scripts
+ mkdir -p upgrade && ./generate_upgrade.sh 3.1.10 && \
+ cp upgrade/* /usr/local/pgsql/share/extension/ && \
export PATH="/usr/local/pgsql/bin:$PATH" && \
make DOCKER=1 -j $(getconf _NPROCESSORS_ONLN) install && \
rm -rf /plv8-* && \
find /usr/local/pgsql/ -name "plv8-*.so" | xargs strip && \
+ # don't break computes with installed old version of plv8
+ cd /usr/local/pgsql/lib/ && \
+ ln -s plv8-3.1.10.so plv8-3.1.5.so && \
+ ln -s plv8-3.1.10.so plv8-3.1.8.so && \
echo 'trusted = true' >> /usr/local/pgsql/share/extension/plv8.control && \
echo 'trusted = true' >> /usr/local/pgsql/share/extension/plcoffee.control && \
echo 'trusted = true' >> /usr/local/pgsql/share/extension/plls.control
@@ -551,6 +546,7 @@ RUN wget https://github.com/rdkit/rdkit/archive/refs/tags/Release_2023_03_3.tar.
-D PostgreSQL_TYPE_INCLUDE_DIR=`pg_config --includedir-server` \
-D PostgreSQL_LIBRARY_DIR=`pg_config --libdir` \
-D RDK_INSTALL_INTREE=OFF \
+ -D RDK_INSTALL_COMIC_FONTS=OFF \
-D CMAKE_BUILD_TYPE=Release \
. && \
make -j $(getconf _NPROCESSORS_ONLN) && \
@@ -617,6 +613,7 @@ RUN wget https://github.com/theory/pg-semver/archive/refs/tags/v0.32.1.tar.gz -O
FROM build-deps AS pg-embedding-pg-build
COPY --from=pg-build /usr/local/pgsql/ /usr/local/pgsql/
+ARG PG_VERSION
ENV PATH "/usr/local/pgsql/bin/:$PATH"
RUN case "${PG_VERSION}" in \
"v14" | "v15") \
@@ -779,6 +776,8 @@ RUN wget https://github.com/eulerto/wal2json/archive/refs/tags/wal2json_2_5.tar.
#
#########################################################################################
FROM build-deps AS neon-pg-ext-build
+ARG PG_VERSION
+
# Public extensions
COPY --from=postgis-build /usr/local/pgsql/ /usr/local/pgsql/
COPY --from=postgis-build /sfcgal/* /
diff --git a/compute_tools/src/compute.rs b/compute_tools/src/compute.rs
index 5f5363105c..07e0abe6ff 100644
--- a/compute_tools/src/compute.rs
+++ b/compute_tools/src/compute.rs
@@ -700,13 +700,14 @@ impl ComputeNode {
// In this case we need to connect with old `zenith_admin` name
// and create new user. We cannot simply rename connected user,
// but we can create a new one and grant it all privileges.
- let mut client = match Client::connect(self.connstr.as_str(), NoTls) {
+ let connstr = self.connstr.clone();
+ let mut client = match Client::connect(connstr.as_str(), NoTls) {
Err(e) => {
info!(
"cannot connect to postgres: {}, retrying with `zenith_admin` username",
e
);
- let mut zenith_admin_connstr = self.connstr.clone();
+ let mut zenith_admin_connstr = connstr.clone();
zenith_admin_connstr
.set_username("zenith_admin")
@@ -719,8 +720,8 @@ impl ComputeNode {
client.simple_query("GRANT zenith_admin TO cloud_admin")?;
drop(client);
- // reconnect with connsting with expected name
- Client::connect(self.connstr.as_str(), NoTls)?
+ // reconnect with connstring with expected name
+ Client::connect(connstr.as_str(), NoTls)?
}
Ok(client) => client,
};
@@ -734,8 +735,8 @@ impl ComputeNode {
cleanup_instance(&mut client)?;
handle_roles(spec, &mut client)?;
handle_databases(spec, &mut client)?;
- handle_role_deletions(spec, self.connstr.as_str(), &mut client)?;
- handle_grants(spec, &mut client, self.connstr.as_str())?;
+ handle_role_deletions(spec, connstr.as_str(), &mut client)?;
+ handle_grants(spec, &mut client, connstr.as_str())?;
handle_extensions(spec, &mut client)?;
handle_extension_neon(&mut client)?;
create_availability_check_data(&mut client)?;
@@ -743,6 +744,12 @@ impl ComputeNode {
// 'Close' connection
drop(client);
+ if self.has_feature(ComputeFeature::Migrations) {
+ thread::spawn(move || {
+ let mut client = Client::connect(connstr.as_str(), NoTls)?;
+ handle_migrations(&mut client)
+ });
+ }
Ok(())
}
@@ -807,6 +814,10 @@ impl ComputeNode {
handle_grants(&spec, &mut client, self.connstr.as_str())?;
handle_extensions(&spec, &mut client)?;
handle_extension_neon(&mut client)?;
+ // We can skip handle_migrations here because a new migration can only appear
+ // if we have a new version of the compute_ctl binary, which can only happen
+ // if compute got restarted, in which case we'll end up inside of apply_config
+ // instead of reconfigure.
}
// 'Close' connection
diff --git a/compute_tools/src/spec.rs b/compute_tools/src/spec.rs
index ef5f55622d..e87dc0b732 100644
--- a/compute_tools/src/spec.rs
+++ b/compute_tools/src/spec.rs
@@ -727,3 +727,79 @@ pub fn handle_extension_neon(client: &mut Client) -> Result<()> {
Ok(())
}
+
+#[instrument(skip_all)]
+pub fn handle_migrations(client: &mut Client) -> Result<()> {
+ info!("handle migrations");
+
+ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ // !BE SURE TO ONLY ADD MIGRATIONS TO THE END OF THIS ARRAY. IF YOU DO NOT, VERY VERY BAD THINGS MAY HAPPEN!
+ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ let migrations = [
+ "ALTER ROLE neon_superuser BYPASSRLS",
+ r#"
+DO $$
+DECLARE
+ role_name text;
+BEGIN
+ FOR role_name IN SELECT rolname FROM pg_roles WHERE pg_has_role(rolname, 'neon_superuser', 'member')
+ LOOP
+ RAISE NOTICE 'EXECUTING ALTER ROLE % INHERIT', quote_ident(role_name);
+ EXECUTE 'ALTER ROLE ' || quote_ident(role_name) || ' INHERIT';
+ END LOOP;
+
+ FOR role_name IN SELECT rolname FROM pg_roles
+ WHERE
+ NOT pg_has_role(rolname, 'neon_superuser', 'member') AND NOT starts_with(rolname, 'pg_')
+ LOOP
+ RAISE NOTICE 'EXECUTING ALTER ROLE % NOBYPASSRLS', quote_ident(role_name);
+ EXECUTE 'ALTER ROLE ' || quote_ident(role_name) || ' NOBYPASSRLS';
+ END LOOP;
+END $$;
+"#,
+ ];
+
+ let mut query = "CREATE SCHEMA IF NOT EXISTS neon_migration";
+ client.simple_query(query)?;
+
+ query = "CREATE TABLE IF NOT EXISTS neon_migration.migration_id (key INT NOT NULL PRIMARY KEY, id bigint NOT NULL DEFAULT 0)";
+ client.simple_query(query)?;
+
+ query = "INSERT INTO neon_migration.migration_id VALUES (0, 0) ON CONFLICT DO NOTHING";
+ client.simple_query(query)?;
+
+ query = "ALTER SCHEMA neon_migration OWNER TO cloud_admin";
+ client.simple_query(query)?;
+
+ query = "REVOKE ALL ON SCHEMA neon_migration FROM PUBLIC";
+ client.simple_query(query)?;
+
+ query = "SELECT id FROM neon_migration.migration_id";
+ let row = client.query_one(query, &[])?;
+ let mut current_migration: usize = row.get::<&str, i64>("id") as usize;
+ let starting_migration_id = current_migration;
+
+ query = "BEGIN";
+ client.simple_query(query)?;
+
+ while current_migration < migrations.len() {
+ info!("Running migration:\n{}\n", migrations[current_migration]);
+ client.simple_query(migrations[current_migration])?;
+ current_migration += 1;
+ }
+ let setval = format!(
+ "UPDATE neon_migration.migration_id SET id={}",
+ migrations.len()
+ );
+ client.simple_query(&setval)?;
+
+ query = "COMMIT";
+ client.simple_query(query)?;
+
+ info!(
+ "Ran {} migrations",
+ (migrations.len() - starting_migration_id)
+ );
+ Ok(())
+}
diff --git a/control_plane/Cargo.toml b/control_plane/Cargo.toml
index 898ad05add..09c171f1d3 100644
--- a/control_plane/Cargo.toml
+++ b/control_plane/Cargo.toml
@@ -10,6 +10,8 @@ async-trait.workspace = true
camino.workspace = true
clap.workspace = true
comfy-table.workspace = true
+diesel = { version = "2.1.4", features = ["postgres"]}
+diesel_migrations = { version = "2.1.0", features = ["postgres"]}
futures.workspace = true
git-version.workspace = true
nix.workspace = true
@@ -19,6 +21,7 @@ hex.workspace = true
hyper.workspace = true
regex.workspace = true
reqwest = { workspace = true, features = ["blocking", "json"] }
+scopeguard.workspace = true
serde.workspace = true
serde_json.workspace = true
serde_with.workspace = true
diff --git a/control_plane/attachment_service/Cargo.toml b/control_plane/attachment_service/Cargo.toml
index 2e2286dbab..6fc21810bc 100644
--- a/control_plane/attachment_service/Cargo.toml
+++ b/control_plane/attachment_service/Cargo.toml
@@ -25,6 +25,8 @@ tracing.workspace = true
# a parsing function when loading pageservers from neon_local LocalEnv
postgres_backend.workspace = true
+diesel = { version = "2.1.4", features = ["serde_json", "postgres"] }
+
utils = { path = "../../libs/utils/" }
metrics = { path = "../../libs/metrics/" }
control_plane = { path = ".." }
diff --git a/control_plane/attachment_service/migrations/.keep b/control_plane/attachment_service/migrations/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/control_plane/attachment_service/migrations/00000000000000_diesel_initial_setup/down.sql b/control_plane/attachment_service/migrations/00000000000000_diesel_initial_setup/down.sql
new file mode 100644
index 0000000000..a9f5260911
--- /dev/null
+++ b/control_plane/attachment_service/migrations/00000000000000_diesel_initial_setup/down.sql
@@ -0,0 +1,6 @@
+-- This file was automatically created by Diesel to setup helper functions
+-- and other internal bookkeeping. This file is safe to edit, any future
+-- changes will be added to existing projects as new migrations.
+
+DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass);
+DROP FUNCTION IF EXISTS diesel_set_updated_at();
diff --git a/control_plane/attachment_service/migrations/00000000000000_diesel_initial_setup/up.sql b/control_plane/attachment_service/migrations/00000000000000_diesel_initial_setup/up.sql
new file mode 100644
index 0000000000..d68895b1a7
--- /dev/null
+++ b/control_plane/attachment_service/migrations/00000000000000_diesel_initial_setup/up.sql
@@ -0,0 +1,36 @@
+-- This file was automatically created by Diesel to setup helper functions
+-- and other internal bookkeeping. This file is safe to edit, any future
+-- changes will be added to existing projects as new migrations.
+
+
+
+
+-- Sets up a trigger for the given table to automatically set a column called
+-- `updated_at` whenever the row is modified (unless `updated_at` was included
+-- in the modified columns)
+--
+-- # Example
+--
+-- ```sql
+-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW());
+--
+-- SELECT diesel_manage_updated_at('users');
+-- ```
+CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$
+BEGIN
+ EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s
+ FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl);
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD AND
+ NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at
+ ) THEN
+ NEW.updated_at := current_timestamp;
+ END IF;
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
diff --git a/control_plane/attachment_service/migrations/2024-01-07-211257_create_tenant_shards/down.sql b/control_plane/attachment_service/migrations/2024-01-07-211257_create_tenant_shards/down.sql
new file mode 100644
index 0000000000..b875b91c00
--- /dev/null
+++ b/control_plane/attachment_service/migrations/2024-01-07-211257_create_tenant_shards/down.sql
@@ -0,0 +1 @@
+DROP TABLE tenant_shards;
diff --git a/control_plane/attachment_service/migrations/2024-01-07-211257_create_tenant_shards/up.sql b/control_plane/attachment_service/migrations/2024-01-07-211257_create_tenant_shards/up.sql
new file mode 100644
index 0000000000..585dbc79a0
--- /dev/null
+++ b/control_plane/attachment_service/migrations/2024-01-07-211257_create_tenant_shards/up.sql
@@ -0,0 +1,12 @@
+CREATE TABLE tenant_shards (
+ tenant_id VARCHAR NOT NULL,
+ shard_number INTEGER NOT NULL,
+ shard_count INTEGER NOT NULL,
+ PRIMARY KEY(tenant_id, shard_number, shard_count),
+ shard_stripe_size INTEGER NOT NULL,
+ generation INTEGER NOT NULL,
+ generation_pageserver BIGINT NOT NULL,
+ placement_policy VARCHAR NOT NULL,
+ -- config is JSON encoded, opaque to the database.
+ config TEXT NOT NULL
+);
\ No newline at end of file
diff --git a/control_plane/attachment_service/migrations/2024-01-07-212945_create_nodes/down.sql b/control_plane/attachment_service/migrations/2024-01-07-212945_create_nodes/down.sql
new file mode 100644
index 0000000000..ec303bc8cf
--- /dev/null
+++ b/control_plane/attachment_service/migrations/2024-01-07-212945_create_nodes/down.sql
@@ -0,0 +1 @@
+DROP TABLE nodes;
diff --git a/control_plane/attachment_service/migrations/2024-01-07-212945_create_nodes/up.sql b/control_plane/attachment_service/migrations/2024-01-07-212945_create_nodes/up.sql
new file mode 100644
index 0000000000..9be0880fa4
--- /dev/null
+++ b/control_plane/attachment_service/migrations/2024-01-07-212945_create_nodes/up.sql
@@ -0,0 +1,10 @@
+CREATE TABLE nodes (
+ node_id BIGINT PRIMARY KEY NOT NULL,
+
+ scheduling_policy VARCHAR NOT NULL,
+
+ listen_http_addr VARCHAR NOT NULL,
+ listen_http_port INTEGER NOT NULL,
+ listen_pg_addr VARCHAR NOT NULL,
+ listen_pg_port INTEGER NOT NULL
+);
\ No newline at end of file
diff --git a/control_plane/attachment_service/src/http.rs b/control_plane/attachment_service/src/http.rs
index 30f6dd66ee..81f21a8e7a 100644
--- a/control_plane/attachment_service/src/http.rs
+++ b/control_plane/attachment_service/src/http.rs
@@ -1,5 +1,5 @@
use crate::reconciler::ReconcileError;
-use crate::service::Service;
+use crate::service::{Service, STARTUP_RECONCILE_TIMEOUT};
use hyper::{Body, Request, Response};
use hyper::{StatusCode, Uri};
use pageserver_api::models::{TenantCreateRequest, TimelineCreateRequest};
@@ -104,34 +104,34 @@ async fn handle_inspect(mut req: Request
) -> Result, ApiErr
json_response(StatusCode::OK, state.service.inspect(inspect_req))
}
-async fn handle_tenant_create(mut req: Request) -> Result, ApiError> {
+async fn handle_tenant_create(
+ service: Arc,
+ mut req: Request,
+) -> Result, ApiError> {
let create_req = json_request::(&mut req).await?;
- let state = get_state(&req);
- json_response(
- StatusCode::OK,
- state.service.tenant_create(create_req).await?,
- )
+ json_response(StatusCode::OK, service.tenant_create(create_req).await?)
}
-async fn handle_tenant_timeline_create(mut req: Request) -> Result, ApiError> {
+async fn handle_tenant_timeline_create(
+ service: Arc,
+ mut req: Request,
+) -> Result, ApiError> {
let tenant_id: TenantId = parse_request_param(&req, "tenant_id")?;
let create_req = json_request::(&mut req).await?;
-
- let state = get_state(&req);
json_response(
StatusCode::OK,
- state
- .service
+ service
.tenant_timeline_create(tenant_id, create_req)
.await?,
)
}
-async fn handle_tenant_locate(req: Request) -> Result, ApiError> {
+async fn handle_tenant_locate(
+ service: Arc,
+ req: Request,
+) -> Result, ApiError> {
let tenant_id: TenantId = parse_request_param(&req, "tenant_id")?;
- let state = get_state(&req);
-
- json_response(StatusCode::OK, state.service.tenant_locate(tenant_id)?)
+ json_response(StatusCode::OK, service.tenant_locate(tenant_id)?)
}
async fn handle_node_register(mut req: Request) -> Result, ApiError> {
@@ -154,14 +154,15 @@ async fn handle_node_configure(mut req: Request) -> Result,
json_response(StatusCode::OK, state.service.node_configure(config_req)?)
}
-async fn handle_tenant_shard_migrate(mut req: Request) -> Result, ApiError> {
+async fn handle_tenant_shard_migrate(
+ service: Arc,
+ mut req: Request,
+) -> Result, ApiError> {
let tenant_shard_id: TenantShardId = parse_request_param(&req, "tenant_shard_id")?;
let migrate_req = json_request::(&mut req).await?;
- let state = get_state(&req);
json_response(
StatusCode::OK,
- state
- .service
+ service
.tenant_shard_migrate(tenant_shard_id, migrate_req)
.await?,
)
@@ -178,6 +179,35 @@ impl From for ApiError {
}
}
+/// Common wrapper for request handlers that call into Service and will operate on tenants: they must only
+/// be allowed to run if Service has finished its initial reconciliation.
+async fn tenant_service_handler(request: Request, handler: H) -> R::Output
+where
+ R: std::future::Future