From 3fdef909336edd99f0700524da9f10eb5867d68e Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Fri, 16 May 2025 19:04:18 -0700 Subject: [PATCH] Go back in time --- .github/FUNDING.yml | 15 - .github/workflows/ci.yml | 10 +- .github/workflows/package.yml | 103 +- .gitignore | 6 +- Cargo.lock | 4438 +++++++++++++++++ Cargo.toml | 9 + dev/new.sh | 9 + .../pgbouncer_benchmark/Dockerfile.pgbouncer | 6 + examples/pgbouncer_benchmark/README.md | 31 + .../pgbouncer_benchmark/docker-compose.yml | 24 + examples/pgbouncer_benchmark/pgbouncer.ini | 10 + examples/pgbouncer_benchmark/pgdog.toml | 9 + examples/pgbouncer_benchmark/userlist.txt | 1 + examples/pgbouncer_benchmark/users.toml | 4 + flamegraph.svg | 491 ++ integration/go/dev.sh | 8 + integration/go/go.mod | 17 + integration/go/go.sum | 28 + integration/go/pg_tests.go | 7 + integration/go/pg_tests_test.go | 129 + integration/go/run.sh | 11 + integration/load_balancer/docker-compose.yml | 25 + integration/load_balancer/docker/primary.sh | 7 + integration/load_balancer/docker/replica.sh | 35 + integration/load_balancer/pgdog.sh | 17 + integration/load_balancer/pgdog.toml | 45 + integration/load_balancer/requirements.txt | 20 + integration/load_balancer/test_lb_asyncpy.py | 82 + integration/load_balancer/users.toml | 4 + integration/pgbench/dev.sh | 2 +- integration/pgdog.toml | 15 +- integration/python/dev.sh | 2 +- integration/python/requirements.txt | 13 +- integration/python/test_asyncpg.py | 40 +- integration/python/test_sqlalchemy.py | 96 + integration/rust/dev.sh | 2 +- integration/rust/src/setup.rs | 20 +- integration/rust/tests/integration/auth.rs | 43 + .../tests/integration/fake_transactions.rs | 54 +- integration/rust/tests/integration/mod.rs | 1 + integration/rust/tests/integration/reload.rs | 1 + integration/rust/tests/sqlx/bad_auth.rs | 2 + integration/setup.sh | 3 +- integration/toxi/dev.sh | 8 +- integration/toxi/rspec_helper.rb | 1 + integration/toxi/toxi_spec.rb | 6 + pgdog.toml | 106 +- pgdog/Cargo.lock | 1183 +++++ pgdog/Cargo.toml | 1 + pgdog/src/admin/backend.rs | 15 +- pgdog/src/admin/error.rs | 6 + pgdog/src/admin/parser.rs | 2 +- pgdog/src/admin/reload.rs | 2 +- pgdog/src/admin/set.rs | 50 +- pgdog/src/admin/show_clients.rs | 4 +- pgdog/src/admin/show_config.rs | 2 +- pgdog/src/admin/show_pools.rs | 2 + pgdog/src/admin/show_query_cache.rs | 2 +- pgdog/src/admin/show_servers.rs | 7 +- pgdog/src/admin/show_stats.rs | 6 +- pgdog/src/auth/scram/server.rs | 1 + pgdog/src/backend/databases.rs | 92 +- pgdog/src/backend/mod.rs | 1 + pgdog/src/backend/pool/ban.rs | 7 +- pgdog/src/backend/pool/cleanup.rs | 53 +- pgdog/src/backend/pool/cluster.rs | 144 +- pgdog/src/backend/pool/config.rs | 110 +- pgdog/src/backend/pool/connection/binding.rs | 97 +- pgdog/src/backend/pool/connection/mirror.rs | 145 + pgdog/src/backend/pool/connection/mod.rs | 106 +- .../pool/connection/multi_shard/mod.rs | 4 +- .../pool/connection/multi_shard/test.rs | 61 + pgdog/src/backend/pool/guard.rs | 133 +- pgdog/src/backend/pool/healthcheck.rs | 22 +- pgdog/src/backend/pool/inner.rs | 242 +- pgdog/src/backend/pool/mod.rs | 4 +- pgdog/src/backend/pool/monitor.rs | 54 +- pgdog/src/backend/pool/pool_impl.rs | 244 +- pgdog/src/backend/pool/replicas.rs | 78 +- pgdog/src/backend/pool/request.rs | 4 +- pgdog/src/backend/pool/state.rs | 7 +- pgdog/src/backend/pool/stats.rs | 47 +- pgdog/src/backend/pool/taken.rs | 53 + pgdog/src/backend/pool/test/mod.rs | 84 +- pgdog/src/backend/pool/test/replica.rs | 2 +- pgdog/src/backend/pool/waiting.rs | 63 +- pgdog/src/backend/prepared_statements.rs | 32 +- pgdog/src/backend/protocol/buffer.rs | 12 - pgdog/src/backend/protocol/mod.rs | 1 - pgdog/src/backend/reload_notify.rs | 33 + .../src/backend/replication/sharded_tables.rs | 2 +- pgdog/src/backend/schema/mod.rs | 54 +- pgdog/src/backend/schema/relation.rs | 15 +- pgdog/src/backend/server.rs | 733 ++- pgdog/src/backend/server_options.rs | 8 +- pgdog/src/backend/stats.rs | 53 +- pgdog/src/config/convert.rs | 6 +- pgdog/src/config/mod.rs | 81 +- pgdog/src/frontend/buffer.rs | 18 +- pgdog/src/frontend/client/inner.rs | 40 +- pgdog/src/frontend/client/mod.rs | 238 +- pgdog/src/frontend/error.rs | 15 + pgdog/src/frontend/listener.rs | 15 +- pgdog/src/frontend/mod.rs | 1 + .../prepared_statements/global_cache.rs | 7 +- pgdog/src/frontend/prepared_statements/mod.rs | 6 +- .../frontend/prepared_statements/request.rs | 2 +- .../frontend/prepared_statements/rewrite.rs | 20 +- pgdog/src/frontend/router/context.rs | 40 + pgdog/src/frontend/router/mod.rs | 20 +- pgdog/src/frontend/router/parser/cache.rs | 6 +- pgdog/src/frontend/router/parser/command.rs | 4 +- pgdog/src/frontend/router/parser/error.rs | 3 + pgdog/src/frontend/router/parser/insert.rs | 21 + pgdog/src/frontend/router/parser/key.rs | 2 + pgdog/src/frontend/router/parser/mod.rs | 1 + .../frontend/router/parser/multi_tenant.rs | 104 + pgdog/src/frontend/router/parser/query.rs | 456 +- pgdog/src/frontend/router/parser/route.rs | 32 + pgdog/src/frontend/router/parser/table.rs | 22 + pgdog/src/frontend/router/parser/value.rs | 7 + .../frontend/router/parser/where_clause.rs | 83 +- pgdog/src/frontend/router/search_path.rs | 53 + pgdog/src/frontend/stats.rs | 9 +- pgdog/src/lib.rs | 41 + pgdog/src/main.rs | 72 +- pgdog/src/net/decoder.rs | 8 +- pgdog/src/net/messages/auth/password.rs | 1 + pgdog/src/net/messages/bind.rs | 180 +- pgdog/src/net/messages/command_complete.rs | 67 +- pgdog/src/net/messages/describe.rs | 47 +- pgdog/src/net/messages/error_response.rs | 14 + pgdog/src/net/messages/execute.rs | 11 +- pgdog/src/net/messages/hello.rs | 18 +- pgdog/src/net/messages/mod.rs | 2 +- pgdog/src/net/messages/notice_response.rs | 23 + pgdog/src/net/messages/parse.rs | 175 +- pgdog/src/net/messages/payload.rs | 11 +- pgdog/src/net/messages/query.rs | 6 + pgdog/src/net/mod.rs | 7 +- pgdog/src/net/parameter.rs | 184 +- pgdog/src/net/stream.rs | 37 +- pgdog/src/state.rs | 9 + pgdog/src/stats/logger.rs | 45 + pgdog/src/stats/mod.rs | 2 + pgdog/src/stats/pools.rs | 8 +- pgdog/src/util.rs | 1 + pgdog/tests/pgbench-select-1.sql | 3 + pgdog/tests/pgbench.sh | 5 +- pgdog/tests/pgbouncer/pgbouncer.ini | 2 + pgdog/tests/pgbouncer/pgdog.toml | 2 + users.toml | 27 +- 152 files changed, 10780 insertions(+), 1639 deletions(-) delete mode 100644 .github/FUNDING.yml create mode 100644 Cargo.lock create mode 100644 dev/new.sh create mode 100644 examples/pgbouncer_benchmark/Dockerfile.pgbouncer create mode 100644 examples/pgbouncer_benchmark/README.md create mode 100644 examples/pgbouncer_benchmark/docker-compose.yml create mode 100644 examples/pgbouncer_benchmark/pgbouncer.ini create mode 100644 examples/pgbouncer_benchmark/pgdog.toml create mode 100644 examples/pgbouncer_benchmark/userlist.txt create mode 100644 examples/pgbouncer_benchmark/users.toml create mode 100644 flamegraph.svg create mode 100644 integration/go/dev.sh create mode 100644 integration/go/go.mod create mode 100644 integration/go/go.sum create mode 100644 integration/go/pg_tests.go create mode 100644 integration/go/pg_tests_test.go create mode 100644 integration/go/run.sh create mode 100644 integration/load_balancer/docker-compose.yml create mode 100755 integration/load_balancer/docker/primary.sh create mode 100755 integration/load_balancer/docker/replica.sh create mode 100644 integration/load_balancer/pgdog.sh create mode 100644 integration/load_balancer/pgdog.toml create mode 100644 integration/load_balancer/requirements.txt create mode 100644 integration/load_balancer/test_lb_asyncpy.py create mode 100644 integration/load_balancer/users.toml create mode 100644 integration/rust/tests/integration/auth.rs create mode 100644 pgdog/Cargo.lock create mode 100644 pgdog/src/backend/pool/connection/mirror.rs create mode 100644 pgdog/src/backend/pool/connection/multi_shard/test.rs create mode 100644 pgdog/src/backend/pool/taken.rs delete mode 100644 pgdog/src/backend/protocol/buffer.rs create mode 100644 pgdog/src/backend/reload_notify.rs create mode 100644 pgdog/src/frontend/router/context.rs create mode 100644 pgdog/src/frontend/router/parser/multi_tenant.rs create mode 100644 pgdog/src/frontend/router/search_path.rs create mode 100644 pgdog/src/lib.rs create mode 100644 pgdog/src/stats/logger.rs create mode 100644 pgdog/tests/pgbench-select-1.sql diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 3af973af..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,15 +0,0 @@ -# These are supported funding model platforms - -github: # -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry -polar: # Replace with a single Polar username -buy_me_a_coffee: # -thanks_dev: # Replace with a single thanks.dev username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d127026f..371cb6a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,14 +92,16 @@ jobs: bash integration/toxi/setup.sh - name: Build PgDog run: cargo build --release - - name: Run JS + - name: pgbench + run: bash integration/pgbench/run.sh + - name: Go + run: bash integration/go/run.sh + - name: JavaScript run: bash integration/js/pg_tests/run.sh - - name: Run Toxi + - name: Toxi run: bash integration/toxi/run.sh - name: Python run: bash integration/python/run.sh - - name: pgbench - run: bash integration/pgbench/run.sh - name: Ruby run: bash integration/ruby/run.sh - name: Java diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 9014953f..a5a6be52 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -1,15 +1,23 @@ name: package on: push: - branches: ["main"] + branches: ['main'] workflow_dispatch: env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: - build-and-push-image: - runs-on: ubuntu-latest + build: + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + include: + - platform: linux/amd64 + runner: ubuntu-latest + - platform: linux/arm64 + runner: ubuntu-24.04-arm permissions: contents: read packages: write @@ -19,28 +27,103 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + - name: Prepare + run: | + platform='${{ matrix.platform }}' + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + - name: Log in to the Container registry - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build and push Docker image - id: push - uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + id: build + uses: docker/build-push-action@v6 with: context: . - push: true - tags: ${{ steps.meta.outputs.tags }} + # Only tag by registry + image name to to push by digest + tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} labels: ${{ steps.meta.outputs.labels }} + platforms: ${{ matrix.platform }} + outputs: type=image,push-by-digest=true,name-canonical=true,push=true + + - name: Export digest + run: | + mkdir -p ${{ runner.temp }}/digests + digest="${{ steps.build.outputs.digest }}" + touch "${{ runner.temp }}/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: ${{ runner.temp }}/digests/* + if-no-files-found: error + retention-days: 1 + - name: Generate artifact attestation uses: actions/attest-build-provenance@v2 with: subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} - subject-digest: ${{ steps.push.outputs.digest }} + subject-digest: ${{ steps.build.outputs.digest }} push-to-registry: true + + merge: + runs-on: ubuntu-latest + needs: + - build + permissions: + contents: read + packages: write + attestations: write + id-token: write + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: ${{ runner.temp }}/digests + pattern: digests-* + merge-multiple: true + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - name: Create manifest list and push + working-directory: ${{ runner.temp }}/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *) + + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} diff --git a/.gitignore b/.gitignore index e26cb019..978060a6 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,6 @@ debug/ target/ -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock - # These are backup files generated by rustfmt **/*.rs.bk @@ -44,3 +40,5 @@ toxi.log *.log *.gem *.sqlite3 +perf.data +perf.data.old diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..1bd88efa --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,4438 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys 0.59.0", +] + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "async-trait" +version = "0.1.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "aws-lc-rs" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fcc8f365936c834db5514fc45aee5b1202d677e6b40e48468aaaa8183ca8c7" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079" +dependencies = [ + "bindgen 0.69.5", + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" + +[[package]] +name = "bindgen" +version = "0.66.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +dependencies = [ + "bitflags 2.9.1", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.101", + "which", +] + +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags 2.9.1", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.101", + "which", +] + +[[package]] +name = "bindgen" +version = "0.71.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" +dependencies = [ + "bitflags 2.9.1", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 2.1.1", + "shlex", + "syn 2.0.101", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "bytemuck" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "castaway" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" +dependencies = [ + "rustversion", +] + +[[package]] +name = "cc" +version = "1.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.5.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "compact_str" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "static_assertions", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crossterm" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" +dependencies = [ + "bitflags 2.9.1", + "crossterm_winapi", + "derive_more", + "document-features", + "mio", + "parking_lot", + "rustix 1.0.7", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csscolorparser" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a7d3066da2de787b7f032c736763eb7ae5d355f81a68bab2675a96008b0bf" +dependencies = [ + "lab", + "phf", +] + +[[package]] +name = "csv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" +dependencies = [ + "memchr", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.101", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "deltae" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5729f5117e208430e437df2f4843f5e5952997175992d1414f94c57d61e270b4" + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "euclid" +version = "0.22.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48" +dependencies = [ + "num-traits", +] + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fancy-regex" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +dependencies = [ + "bit-set", + "regex", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "filedescriptor" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" +dependencies = [ + "libc", + "thiserror 1.0.69", + "winapi", +] + +[[package]] +name = "finl_unicode" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94c970b525906eb37d3940083aa65b95e481fc1857d467d13374e1d925cfc163" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin 0.9.8", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "h2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "indoc" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" + +[[package]] +name = "instability" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf9fed6d91cfb734e7476a06bde8300a1b94e217e1b523b6f0cd1a01998c71d" +dependencies = [ + "darling", + "indoc", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "kasuari" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def1b67294a9fdc95eeeeafd1209c7a1b8a82aa0bf80ac2ab2a7d0318e9c7622" +dependencies = [ + "hashbrown", + "thiserror 2.0.12", +] + +[[package]] +name = "lab" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf36173d4167ed999940f804952e6b08197cae5ad5d572eb4db150ce8ad5d58f" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin 0.9.8", +] + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libloading" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" +dependencies = [ + "cfg-if", + "windows-targets 0.53.0", +] + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] +name = "line-clipping" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce9d1fb615cfbfabb113034d9fcd9e717f8f7ccbf5dde59af2bc2dd223f9d26" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "mac_address" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0aeb26bf5e836cc1c341c8106051b573f1766dfa05aa87f0b98be5e51b02303" +dependencies = [ + "nix", + "winapi", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmem" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openssl" +version = "0.10.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +dependencies = [ + "memchr", + "thiserror 2.0.12", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "pest_meta" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "petgraph" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +dependencies = [ + "fixedbitset 0.5.7", + "indexmap", +] + +[[package]] +name = "pg_query" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f71c7c56dfe299ec6f98aa210aa23458be3b0610c485be60a5873c2f3627c40e" +dependencies = [ + "bindgen 0.66.1", + "cc", + "fs_extra", + "glob", + "itertools 0.10.5", + "prost", + "prost-build", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "pgdog" +version = "0.1.0" +dependencies = [ + "arc-swap", + "async-trait", + "base64 0.22.1", + "bytes", + "cc", + "chrono", + "clap", + "csv-core", + "fnv", + "futures", + "http-body-util", + "hyper", + "hyper-util", + "md5", + "once_cell", + "parking_lot", + "pg_query", + "pgdog-plugin", + "pin-project", + "rand 0.8.5", + "ratatui", + "regex", + "rmp-serde", + "rustls-native-certs", + "rustls-pki-types", + "scram", + "serde", + "serde_json", + "socket2", + "thiserror 2.0.12", + "tikv-jemallocator", + "tokio", + "tokio-rustls", + "tokio-util", + "toml", + "tracing", + "tracing-subscriber", + "url", + "uuid", +] + +[[package]] +name = "pgdog-plugin" +version = "0.1.1" +dependencies = [ + "bindgen 0.71.1", + "libc", + "libloading", + "tracing", +] + +[[package]] +name = "pgdog-routing" +version = "0.1.0" +dependencies = [ + "cc", + "csv", + "once_cell", + "pg_query", + "pgdog-plugin", + "postgres", + "rand 0.8.5", + "regex", + "tracing", + "tracing-subscriber", + "uuid", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "postgres" +version = "0.19.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "363e6dfbdd780d3aa3597b6eb430db76bb315fa9bad7fae595bb8def808b8470" +dependencies = [ + "bytes", + "fallible-iterator", + "futures-util", + "log", + "tokio", + "tokio-postgres", +] + +[[package]] +name = "postgres-protocol" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54" +dependencies = [ + "base64 0.22.1", + "byteorder", + "bytes", + "fallible-iterator", + "hmac", + "md-5", + "memchr", + "rand 0.9.1", + "sha2", + "stringprep", +] + +[[package]] +name = "postgres-types" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" +dependencies = [ + "bytes", + "fallible-iterator", + "postgres-protocol", + "uuid", +] + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" +dependencies = [ + "proc-macro2", + "syn 2.0.101", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +dependencies = [ + "heck", + "itertools 0.14.0", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.101", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "prost-types" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +dependencies = [ + "prost", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "ratatui" +version = "0.30.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39fbb739119e808c9d3121bb62f434dc8104c83f31b1e0726b6e8a73c80b83eb" +dependencies = [ + "instability", + "ratatui-core", + "ratatui-crossterm", + "ratatui-macros", + "ratatui-termwiz", + "ratatui-widgets", +] + +[[package]] +name = "ratatui-core" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e72d14ff9b26a022827e9b97c546f0d044dc0b689a2dabd1a4698a887db8f4b" +dependencies = [ + "bitflags 2.9.1", + "compact_str", + "hashbrown", + "indoc", + "itertools 0.13.0", + "kasuari", + "lru", + "strum", + "thiserror 2.0.12", + "unicode-segmentation", + "unicode-truncate", + "unicode-width", +] + +[[package]] +name = "ratatui-crossterm" +version = "0.1.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e646757509d030d44f7b01ee774da78b2451d0d540a2652ab4eb7d54c6d74c7" +dependencies = [ + "crossterm", + "instability", + "ratatui-core", +] + +[[package]] +name = "ratatui-macros" +version = "0.7.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809b8926533c1f1e5fa5e26b25593146798d971d709c4a89084911f66140e6d4" +dependencies = [ + "ratatui-core", + "ratatui-widgets", +] + +[[package]] +name = "ratatui-termwiz" +version = "0.1.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5acd5fe259ff4d8e027eac64755ef5d8d5a5ea498b88abeab3449370b4a39510" +dependencies = [ + "ratatui-core", + "termwiz", +] + +[[package]] +name = "ratatui-widgets" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "961633cb7cabfcd341a11f4b8e922279ee62b7d908b1f2606c2be847cd7ede61" +dependencies = [ + "bitflags 2.9.1", + "hashbrown", + "indoc", + "instability", + "itertools 0.13.0", + "line-clipping", + "ratatui-core", + "strum", + "time", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "redox_syscall" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "routing-plugin" +version = "0.1.0" +dependencies = [ + "pgdog-plugin", +] + +[[package]] +name = "rsa" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "futures-util", + "serial_test", + "sqlx", + "tokio", + "tokio-postgres", + "uuid", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys 0.9.4", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.23.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.2.0", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +dependencies = [ + "aws-lc-rs", + "ring 0.17.14", + "rustls-pki-types", + "untrusted 0.9.0", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scc" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22b2d775fb28f245817589471dd49c5edf64237f4a19d10ce9a92ff4651a27f4" +dependencies = [ + "sdd", +] + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scram" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7679a5e6b97bac99b2c208894ba0d34b17d9657f0b728c1cd3bf1c5f7f6ebe88" +dependencies = [ + "base64 0.13.1", + "rand 0.8.5", + "ring 0.16.20", +] + +[[package]] +name = "sdd" +version = "3.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21" + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.1", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +dependencies = [ + "bitflags 2.9.1", + "core-foundation 0.10.0", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serial_test" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" +dependencies = [ + "futures", + "log", + "once_cell", + "parking_lot", + "scc", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlx" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c3a85280daca669cfd3bcb68a337882a8bc57ec882f72c5d13a430613a738e" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f743f2a3cea30a58cd479013f75550e879009e3a02f616f18ca699335aa248c3" +dependencies = [ + "base64 0.22.1", + "bytes", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown", + "hashlink", + "indexmap", + "log", + "memchr", + "native-tls", + "once_cell", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "thiserror 2.0.12", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4200e0fde19834956d4252347c12a083bdcb237d7a1a1446bffd8768417dce" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.101", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ceaa29cade31beca7129b6beeb05737f44f82dbe2a9806ecea5a7093d00b7" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.101", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0afdd3aa7a629683c2d750c2df343025545087081ab5942593a5288855b1b7a7" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.9.1", + "byteorder", + "bytes", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand 0.8.5", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.12", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0bedbe1bbb5e2615ef347a5e9d8cd7680fb63e77d9dafc0f29be15e53f1ebe6" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.9.1", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.12", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c26083e9a520e8eb87a06b12347679b142dc2ea29e6e409f805644a7a979a5bc" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "thiserror 2.0.12", + "tracing", + "url", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.101", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix 1.0.7", + "windows-sys 0.59.0", +] + +[[package]] +name = "terminfo" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ea810f0692f9f51b382fff5893887bb4580f5fa246fde546e0b13e7fcee662" +dependencies = [ + "fnv", + "nom", + "phf", + "phf_codegen", +] + +[[package]] +name = "termios" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" +dependencies = [ + "libc", +] + +[[package]] +name = "termwiz" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bitflags 2.9.1", + "fancy-regex", + "filedescriptor", + "finl_unicode", + "fixedbitset 0.4.2", + "hex", + "lazy_static", + "libc", + "log", + "memmem", + "nix", + "num-derive", + "num-traits", + "ordered-float", + "pest", + "pest_derive", + "phf", + "sha2", + "signal-hook", + "siphasher", + "terminfo", + "termios", + "thiserror 1.0.69", + "ucd-trie", + "unicode-segmentation", + "vtparse", + "wezterm-bidi", + "wezterm-blob-leases", + "wezterm-color-types", + "wezterm-dynamic", + "wezterm-input-types", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tikv-jemalloc-sys" +version = "0.6.0+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3c60906412afa9c2b5b5a48ca6a5abe5736aec9eb48ad05037a677e52e4e2d" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "tikv-jemallocator" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cec5ff18518d81584f477e9bfdf957f5bb0979b0bac3af4ca30b5b3ae2d2865" +dependencies = [ + "libc", + "tikv-jemalloc-sys", +] + +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "tokio-postgres" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0" +dependencies = [ + "async-trait", + "byteorder", + "bytes", + "fallible-iterator", + "futures-channel", + "futures-util", + "log", + "parking_lot", + "percent-encoding", + "phf", + "pin-project-lite", + "postgres-protocol", + "postgres-types", + "rand 0.9.1", + "socket2", + "tokio", + "tokio-util", + "whoami", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "futures-util", + "hashbrown", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-truncate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fbf03860ff438702f3910ca5f28f8dac63c1c11e7efb5012b8b175493606330" +dependencies = [ + "itertools 0.13.0", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +dependencies = [ + "atomic", + "getrandom 0.3.3", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vtparse" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9b2acfb050df409c972a37d3b8e08cdea3bddb0c09db9d53137e504cfabed0" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.101", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wezterm-bidi" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0a6e355560527dd2d1cf7890652f4f09bb3433b6aadade4c9b5ed76de5f3ec" +dependencies = [ + "log", + "wezterm-dynamic", +] + +[[package]] +name = "wezterm-blob-leases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692daff6d93d94e29e4114544ef6d5c942a7ed998b37abdc19b17136ea428eb7" +dependencies = [ + "getrandom 0.3.3", + "mac_address", + "sha2", + "thiserror 1.0.69", + "uuid", +] + +[[package]] +name = "wezterm-color-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de81ef35c9010270d63772bebef2f2d6d1f2d20a983d27505ac850b8c4b4296" +dependencies = [ + "csscolorparser", + "deltae", + "lazy_static", + "wezterm-dynamic", +] + +[[package]] +name = "wezterm-dynamic" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2ab60e120fd6eaa68d9567f3226e876684639d22a4219b313ff69ec0ccd5ac" +dependencies = [ + "log", + "ordered-float", + "strsim", + "thiserror 1.0.69", + "wezterm-dynamic-derive", +] + +[[package]] +name = "wezterm-dynamic-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c0cf2d539c645b448eaffec9ec494b8b19bd5077d9e58cb1ae7efece8d575b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "wezterm-input-types" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7012add459f951456ec9d6c7e6fc340b1ce15d6fc9629f8c42853412c029e57e" +dependencies = [ + "bitflags 1.3.2", + "euclid", + "lazy_static", + "serde", + "wezterm-dynamic", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.44", +] + +[[package]] +name = "whoami" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" +dependencies = [ + "redox_syscall", + "wasite", + "web-sys", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] diff --git a/Cargo.toml b/Cargo.toml index ac0f2375..a24216af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,15 @@ members = [ ] resolver = "2" +# [patch.crates-io] +# tokio = { path = "../tokio/tokio" } + [profile.release] codegen-units = 1 lto = true + +[profile.flamegraph] +inherits = "release" +lto = false +codegen-units = 16 +debug = true diff --git a/dev/new.sh b/dev/new.sh new file mode 100644 index 00000000..0c4a8506 --- /dev/null +++ b/dev/new.sh @@ -0,0 +1,9 @@ +#!/bin/bash +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +branch=$(echo "$USER-$@" | sed 's/\ /\-/g' | tr '[:upper]' '[:lower]') + +git reset --hard origin/main +git checkout main +git pull origin main +git checkout -b "$branch" diff --git a/examples/pgbouncer_benchmark/Dockerfile.pgbouncer b/examples/pgbouncer_benchmark/Dockerfile.pgbouncer new file mode 100644 index 00000000..6eadf3fc --- /dev/null +++ b/examples/pgbouncer_benchmark/Dockerfile.pgbouncer @@ -0,0 +1,6 @@ +FROM ubuntu:latest +RUN apt update && apt install pgbouncer -y +RUN ls /etc +USER ubuntu +WORKDIR /etc +ENTRYPOINT ["pgbouncer", "/etc/pgbouncer.ini"] diff --git a/examples/pgbouncer_benchmark/README.md b/examples/pgbouncer_benchmark/README.md new file mode 100644 index 00000000..43bfcb21 --- /dev/null +++ b/examples/pgbouncer_benchmark/README.md @@ -0,0 +1,31 @@ +### Setup + +1. Make sure you don't have anything running on ports 6433 and 6432. +2. (Optional) Delete all previous images to make sure to pull latest from Hub: `docker rm -vf $(docker ps -aq)` and `docker rmi -f $(docker images -aq)` +3. `docker-compose up` + + +### Run the benchmark + +```bash +export PGHOST=127.0.0.1 +export PGPASSWORD=postgres +export PGUSER=postgres +export PGDATABASE=postgres +``` + +### PgBouncer + +```bash +export PGPORT=6432 +pgbench -i +pgbench -c 10 -t 100000 +``` + +### PgDog + +```bash +export PGPORT=6433 +pgbench -i +pgbench -c 10 -t 100000 +``` diff --git a/examples/pgbouncer_benchmark/docker-compose.yml b/examples/pgbouncer_benchmark/docker-compose.yml new file mode 100644 index 00000000..43f58057 --- /dev/null +++ b/examples/pgbouncer_benchmark/docker-compose.yml @@ -0,0 +1,24 @@ +services: + postgres: + image: postgres:17 + environment: + POSTGRES_PASSWORD: postgres + pgbouncer: + depends_on: + - postgres + build: + dockerfile: ./Dockerfile.pgbouncer + volumes: + - ./pgbouncer.ini:/etc/pgbouncer.ini + - ./userlist.txt:/etc/userlist.txt + ports: + - 6433:6433 + pgdog: + depends_on: + - postgres + image: ghcr.io/pgdogdev/pgdog:main + volumes: + - ./pgdog.toml:/pgdog/pgdog.toml + - ./users.toml:/pgdog/users.toml + ports: + - 6432:6432 diff --git a/examples/pgbouncer_benchmark/pgbouncer.ini b/examples/pgbouncer_benchmark/pgbouncer.ini new file mode 100644 index 00000000..24453400 --- /dev/null +++ b/examples/pgbouncer_benchmark/pgbouncer.ini @@ -0,0 +1,10 @@ +[pgbouncer] +listen_addr = 0.0.0.0 +listen_port = 6433 +pool_mode = transaction +default_pool_size = 10 +auth_file = userlist.txt +max_client_conn = 10000 + +[databases] +postgres = host=postgres port=5432 user=postgres password=postgres diff --git a/examples/pgbouncer_benchmark/pgdog.toml b/examples/pgbouncer_benchmark/pgdog.toml new file mode 100644 index 00000000..79e2d6fb --- /dev/null +++ b/examples/pgbouncer_benchmark/pgdog.toml @@ -0,0 +1,9 @@ +[general] +default_pool_size = 10 +prepared_statements = "disabled" +min_pool_size = 0 + +[[databases]] +name = "postgres" +host = "postgres" +port = 5432 diff --git a/examples/pgbouncer_benchmark/userlist.txt b/examples/pgbouncer_benchmark/userlist.txt new file mode 100644 index 00000000..9a6c4de2 --- /dev/null +++ b/examples/pgbouncer_benchmark/userlist.txt @@ -0,0 +1 @@ +"postgres" "postgres" diff --git a/examples/pgbouncer_benchmark/users.toml b/examples/pgbouncer_benchmark/users.toml new file mode 100644 index 00000000..2cc29855 --- /dev/null +++ b/examples/pgbouncer_benchmark/users.toml @@ -0,0 +1,4 @@ +[[users]] +name = "postgres" +password = "postgres" +database = "postgres" diff --git a/flamegraph.svg b/flamegraph.svg new file mode 100644 index 00000000..2409b379 --- /dev/null +++ b/flamegraph.svg @@ -0,0 +1,491 @@ +Flame Graph Reset ZoomSearch [ld-linux-x86-64.so.2] (2,383,844 samples, 0.01%)[ld-linux-x86-64.so.2] (2,383,844 samples, 0.01%)[ld-linux-x86-64.so.2] (2,383,844 samples, 0.01%)[ld-linux-x86-64.so.2] (2,383,844 samples, 0.01%)[ld-linux-x86-64.so.2] (2,383,844 samples, 0.01%)[ld-linux-x86-64.so.2] (2,383,844 samples, 0.01%)asm_exc_page_fault (2,383,844 samples, 0.01%)exc_page_fault (2,383,844 samples, 0.01%)do_user_addr_fault (2,383,844 samples, 0.01%)handle_mm_fault (2,383,844 samples, 0.01%)__handle_mm_fault (2,383,844 samples, 0.01%)do_fault (2,383,844 samples, 0.01%)finish_fault (2,383,844 samples, 0.01%)set_pte_range (2,383,844 samples, 0.01%)folio_add_new_anon_rmap (2,383,844 samples, 0.01%)__folio_mod_stat (2,383,844 samples, 0.01%)__lruvec_stat_mod_folio (2,383,844 samples, 0.01%)__mod_memcg_lruvec_state (2,383,844 samples, 0.01%)pgdog::config::ConfigAndUsers::load (8,182,774 samples, 0.03%)toml::de::from_str (8,182,774 samples, 0.03%)pgdog::config::_::<impl serde::de::Deserialize for pgdog::config::Config>::deserialize (8,182,774 samples, 0.03%)<toml::de::Deserializer as serde::de::Deserializer>::deserialize_struct (8,182,774 samples, 0.03%)<toml_edit::de::Deserializer<S> as serde::de::Deserializer>::deserialize_struct (8,182,774 samples, 0.03%)<toml_edit::de::value::ValueDeserializer as serde::de::Deserializer>::deserialize_struct (8,182,774 samples, 0.03%)<toml_edit::de::value::ValueDeserializer as serde::de::Deserializer>::deserialize_any (8,182,774 samples, 0.03%)<toml_edit::de::table::TableDeserializer as serde::de::Deserializer>::deserialize_any (8,182,774 samples, 0.03%)pgdog::config::load (8,257,251 samples, 0.03%)_start (8,259,615 samples, 0.03%)__libc_start_main (8,259,615 samples, 0.03%)[libc.so.6] (8,259,615 samples, 0.03%)main (8,259,615 samples, 0.03%)std::rt::lang_start::_{{closure}} (8,259,615 samples, 0.03%)std::sys::backtrace::__rust_begin_short_backtrace (8,259,615 samples, 0.03%)core::ops::function::FnOnce::call_once (8,259,615 samples, 0.03%)pgdog::main (8,259,615 samples, 0.03%)__x64_sys_close (6,234,811 samples, 0.03%)__fput (6,234,811 samples, 0.03%)mntput_no_expire (6,234,811 samples, 0.03%)entry_SYSCALL_64_after_hwframe (6,365,975 samples, 0.03%)do_syscall_64 (6,365,975 samples, 0.03%)rustls_native_certs::load_pem_certs (7,003,086 samples, 0.03%)rustls_pki_types::pem::PemObject::pem_file_iter (7,003,086 samples, 0.03%)std::fs::File::open (7,003,086 samples, 0.03%)std::fs::OpenOptions::open (7,003,086 samples, 0.03%)std::fs::OpenOptions::_open (7,003,086 samples, 0.03%)std::sys::pal::unix::fs::File::open (7,003,086 samples, 0.03%)std::sys::pal::common::small_c_string::run_path_with_cstr (7,003,086 samples, 0.03%)std::sys::pal::common::small_c_string::run_with_cstr (7,003,086 samples, 0.03%)std::sys::pal::common::small_c_string::run_with_cstr_stack (7,003,086 samples, 0.03%)std::sys::pal::unix::fs::File::open::_{{closure}} (7,003,086 samples, 0.03%)std::sys::pal::unix::fs::File::open_c (7,003,086 samples, 0.03%)std::sys::pal::unix::cvt_r (7,003,086 samples, 0.03%)std::sys::pal::unix::fs::File::open_c::_{{closure}} (7,003,086 samples, 0.03%)open64 (7,003,086 samples, 0.03%)[libc.so.6] (7,003,086 samples, 0.03%)[libc.so.6] (7,003,086 samples, 0.03%)[libc.so.6] (7,003,086 samples, 0.03%)entry_SYSCALL_64_after_hwframe (7,003,086 samples, 0.03%)do_syscall_64 (7,003,086 samples, 0.03%)__x64_sys_openat (7,003,086 samples, 0.03%)do_sys_openat2 (7,003,086 samples, 0.03%)do_filp_open (7,003,086 samples, 0.03%)path_openat (7,003,086 samples, 0.03%)link_path_walk.part.0.constprop.0 (7,003,086 samples, 0.03%)inode_permission (7,003,086 samples, 0.03%)pgdog::pgdog::_{{closure}} (12,753,172 samples, 0.05%)pgdog::net::tls::load (12,753,172 samples, 0.05%)pgdog::net::tls::connector (12,753,172 samples, 0.05%)rustls_native_certs::load_native_certs (12,753,172 samples, 0.05%)rustls_native_certs::CertPaths::load (12,753,172 samples, 0.05%)rustls_native_certs::load_pem_certs_from_dir (12,753,172 samples, 0.05%)std::fs::metadata (5,750,086 samples, 0.02%)std::sys::pal::unix::fs::stat (5,750,086 samples, 0.02%)std::sys::pal::common::small_c_string::run_path_with_cstr (5,750,086 samples, 0.02%)std::sys::pal::common::small_c_string::run_with_cstr (5,750,086 samples, 0.02%)std::sys::pal::common::small_c_string::run_with_cstr_stack (5,750,086 samples, 0.02%)std::sys::pal::unix::fs::stat::_{{closure}} (5,750,086 samples, 0.02%)std::sys::pal::unix::fs::try_statx (5,750,086 samples, 0.02%)std::sys::pal::unix::fs::try_statx::statx (5,750,086 samples, 0.02%)statx (5,750,086 samples, 0.02%)entry_SYSCALL_64_after_hwframe (5,750,086 samples, 0.02%)do_syscall_64 (5,750,086 samples, 0.02%)__x64_sys_statx (5,750,086 samples, 0.02%)do_statx (5,750,086 samples, 0.02%)vfs_statx (5,750,086 samples, 0.02%)filename_lookup (5,750,086 samples, 0.02%)path_lookupat (5,750,086 samples, 0.02%)link_path_walk.part.0.constprop.0 (5,750,086 samples, 0.02%)walk_component (5,750,086 samples, 0.02%)lookup_fast (5,750,086 samples, 0.02%)__d_lookup_rcu (5,750,086 samples, 0.02%)pgdog (30,862,049 samples, 0.13%)<arc_swap::strategy::hybrid::HybridStrategy<Cfg> as arc_swap::strategy::sealed::InnerStrategy<T>>::load::_{{closure}} (8,678,243 samples, 0.04%)<core::hash::sip::Hasher<S> as core::hash::Hasher>::write (21,933,775 samples, 0.09%)<hashbrown::raw::RawTable<T,A> as hashbrown::raw::RawTableClone>::clone_from_spec (3,274,892 samples, 0.01%)hashbrown::raw::RawTable<T,A>::clone_from_impl (3,274,892 samples, 0.01%)core::ptr::mut_ptr::<impl *mut T>::copy_to_nonoverlapping (3,274,892 samples, 0.01%)core::intrinsics::copy_nonoverlapping (3,274,892 samples, 0.01%)<hashbrown::map::HashMap<K,V,S,A> as core::clone::Clone>::clone (13,888,934 samples, 0.06%)<hashbrown::raw::RawTable<T,A> as core::clone::Clone>::clone (9,448,325 samples, 0.04%)hashbrown::raw::RawTable<T,A>::new_uninitialized (6,173,433 samples, 0.03%)hashbrown::raw::RawTableInner::new_uninitialized (6,173,433 samples, 0.03%)<pgdog::frontend::router::parser::aggregate::Aggregate as core::clone::Clone>::clone (18,716,960 samples, 0.08%)<alloc::vec::Vec<T,A> as core::clone::Clone>::clone (4,659,895 samples, 0.02%)alloc::slice::<impl [T]>::to_vec_in (4,659,895 samples, 0.02%)alloc::slice::hack::to_vec (4,659,895 samples, 0.02%)<T as alloc::slice::hack::ConvertVec>::to_vec (4,659,895 samples, 0.02%)<pgdog::frontend::router::parser::route::Route as core::clone::Clone>::clone (10,558,763 samples, 0.04%)bytes::buf::buf_impl::Buf::get_i16 (2,988,220 samples, 0.01%)<bytes::bytes::Bytes as bytes::buf::buf_impl::Buf>::advance (2,988,220 samples, 0.01%)bytes::bytes::Bytes::inc_start (2,988,220 samples, 0.01%)<pgdog::net::messages::bind::Bind as pgdog::net::messages::FromBytes>::from_bytes (57,990,629 samples, 0.24%)<pgdog::net::messages::describe::Describe as pgdog::net::messages::FromBytes>::from_bytes (12,753,559 samples, 0.05%)core::ptr::drop_in_place<bytes::bytes::Bytes> (3,307,308 samples, 0.01%)<bytes::bytes::Bytes as core::ops::drop::Drop>::drop (3,307,308 samples, 0.01%)<alloc::sync::Arc<T,A> as core::clone::Clone>::clone (4,035,754 samples, 0.02%)alloc::sync::Arc<T,A>::inner (4,035,754 samples, 0.02%)core::ptr::non_null::NonNull<T>::as_ref (4,035,754 samples, 0.02%)<pgdog::net::messages::parse::Parse as core::clone::Clone>::clone (14,870,838 samples, 0.06%)<core::option::Option<T> as core::clone::Clone>::clone (2,542,134 samples, 0.01%)<bytes::bytes::Bytes as core::clone::Clone>::clone (2,542,134 samples, 0.01%)<pgdog::net::messages::parse::Parse as pgdog::net::messages::FromBytes>::from_bytes (4,390,207 samples, 0.02%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_buf_read::AsyncBufRead>::poll_fill_buf (5,038,403 samples, 0.02%)core::ptr::mut_ptr::<impl *mut T>::copy_from_nonoverlapping (5,674,291 samples, 0.02%)core::intrinsics::copy_nonoverlapping (5,674,291 samples, 0.02%)<pgdog::net::stream::Stream as tokio::io::async_read::AsyncRead>::poll_read (58,218,068 samples, 0.25%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (29,920,126 samples, 0.13%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_read::AsyncRead>::poll_read (29,920,126 samples, 0.13%)tokio::io::read_buf::ReadBuf::put_slice (13,969,976 samples, 0.06%)core::slice::index::<impl core::ops::index::IndexMut<I> for [T]>::index_mut (3,732,711 samples, 0.02%)<core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::index_mut (3,732,711 samples, 0.02%)core::slice::index::get_offset_len_mut_noubcheck (3,732,711 samples, 0.02%)core::slice::index::get_mut_noubcheck (3,732,711 samples, 0.02%)<tokio::io::util::write_all::WriteAll<W> as core::future::future::Future>::poll (2,922,950 samples, 0.01%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read (4,283,176 samples, 0.02%)mio::io_source::IoSource<T>::do_io (4,283,176 samples, 0.02%)mio::sys::unix::selector::stateless_io_source::IoSourceState::do_io (4,283,176 samples, 0.02%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read::_{{closure}} (4,283,176 samples, 0.02%)<&std::net::tcp::TcpStream as std::io::Read>::read (4,283,176 samples, 0.02%)std::sys::net::connection::socket::TcpStream::read (4,283,176 samples, 0.02%)std::sys::net::connection::socket::unix::Socket::read (4,283,176 samples, 0.02%)std::sys::net::connection::socket::unix::Socket::recv_with_flags (4,283,176 samples, 0.02%)std::sys::pal::unix::cvt (4,283,176 samples, 0.02%)<isize as std::sys::pal::unix::IsMinusOne>::is_minus_one (4,283,176 samples, 0.02%)<tokio::net::tcp::stream::TcpStream as tokio::io::async_read::AsyncRead>::poll_read (19,420,707 samples, 0.08%)tokio::net::tcp::stream::TcpStream::poll_read_priv (19,420,707 samples, 0.08%)tokio::io::poll_evented::PollEvented<E>::poll_read (19,420,707 samples, 0.08%)tokio::runtime::io::registration::Registration::clear_readiness (5,552,306 samples, 0.02%)tokio::runtime::io::scheduled_io::ScheduledIo::clear_readiness (5,552,306 samples, 0.02%)tokio::runtime::io::scheduled_io::ScheduledIo::set_readiness (5,552,306 samples, 0.02%)core::sync::atomic::AtomicUsize::fetch_update (5,552,306 samples, 0.02%)core::sync::atomic::AtomicUsize::compare_exchange_weak (5,552,306 samples, 0.02%)core::sync::atomic::atomic_compare_exchange_weak (5,552,306 samples, 0.02%)pgdog::frontend::client::Client::client_messages::_{{closure}} (5,280,348 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::pool::connection::Connection::send<pgdog::backend::protocol::protocol_message::ProtocolMessage>::{{closure}}> (5,280,348 samples, 0.02%)<tokio::net::tcp::stream::TcpStream as tokio::io::async_write::AsyncWrite>::poll_write (22,571,334 samples, 0.10%)tokio::net::tcp::stream::TcpStream::poll_write_priv (22,571,334 samples, 0.10%)tokio::io::poll_evented::PollEvented<E>::poll_write (22,571,334 samples, 0.10%)<&mio::net::tcp::stream::TcpStream as std::io::Write>::write (18,304,900 samples, 0.08%)mio::io_source::IoSource<T>::do_io (18,304,900 samples, 0.08%)mio::sys::unix::selector::stateless_io_source::IoSourceState::do_io (18,304,900 samples, 0.08%)<&mio::net::tcp::stream::TcpStream as std::io::Write>::write::_{{closure}} (18,304,900 samples, 0.08%)<&std::net::tcp::TcpStream as std::io::Write>::write (18,304,900 samples, 0.08%)std::sys::net::connection::socket::TcpStream::write (18,304,900 samples, 0.08%)std::sys::pal::unix::cvt (13,024,552 samples, 0.05%)<isize as std::sys::pal::unix::IsMinusOne>::is_minus_one (13,024,552 samples, 0.05%)core::ptr::drop_in_place<tokio::loom::std::parking_lot::MutexGuard<tokio::runtime::time::wheel::Wheel>> (4,608,719 samples, 0.02%)core::ptr::drop_in_place<lock_api::mutex::MutexGuard<parking_lot::raw_mutex::RawMutex,tokio::runtime::time::wheel::Wheel>> (4,608,719 samples, 0.02%)<lock_api::mutex::MutexGuard<R,T> as core::ops::drop::Drop>::drop (4,608,719 samples, 0.02%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::unlock (4,608,719 samples, 0.02%)core::sync::atomic::AtomicU8::compare_exchange (4,608,719 samples, 0.02%)core::sync::atomic::atomic_compare_exchange (4,608,719 samples, 0.02%)<tokio::runtime::time::entry::TimerEntry as core::ops::drop::Drop>::drop (13,962,724 samples, 0.06%)tokio::runtime::time::entry::TimerEntry::cancel (13,962,724 samples, 0.06%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::clear_entry (13,962,724 samples, 0.06%)tokio::loom::std::parking_lot::RwLock<T>::read (9,354,005 samples, 0.04%)lock_api::rwlock::RwLock<R,T>::read (9,354,005 samples, 0.04%)<parking_lot::raw_rwlock::RawRwLock as lock_api::rwlock::RawRwLock>::lock_shared (9,354,005 samples, 0.04%)parking_lot::raw_rwlock::RawRwLock::try_lock_shared_fast (9,354,005 samples, 0.04%)core::sync::atomic::AtomicUsize::compare_exchange_weak (4,488,439 samples, 0.02%)core::sync::atomic::atomic_compare_exchange_weak (4,488,439 samples, 0.02%)<tokio::sync::notify::Notified as core::ops::drop::Drop>::drop (23,603,589 samples, 0.10%)tokio::util::linked_list::LinkedList<L,<L as tokio::util::linked_list::Link>::Target>::remove (9,594,543 samples, 0.04%)entry_SYSCALL_64 (3,745,883 samples, 0.02%)<tokio::time::timeout::Timeout<T> as core::future::future::Future>::poll (59,043,387 samples, 0.25%)pgdog::backend::pool::connection::Connection::read::_{{closure}} (47,240,137 samples, 0.20%)pgdog::backend::pool::connection::binding::Binding::read::_{{closure}} (45,168,190 samples, 0.19%)<pgdog::backend::pool::guard::Guard as core::ops::deref::DerefMut>::deref_mut (3,939,941 samples, 0.02%)core::option::Option<T>::as_mut (3,939,941 samples, 0.02%)GFp_sha256_block_data_order_ssse3 (7,491,593 samples, 0.03%)[libc.so.6] (60,647,233 samples, 0.26%)entry_SYSCALL_64 (60,647,233 samples, 0.26%)<core::result::Result<T,E> as core::ops::try_trait::Try>::branch (4,905,736 samples, 0.02%)<std::time::Instant as core::ops::arith::Sub>::sub (2,548,245 samples, 0.01%)std::time::Instant::duration_since (2,548,245 samples, 0.01%)std::time::Instant::checked_duration_since (2,548,245 samples, 0.01%)std::sys::pal::unix::time::Instant::checked_sub_instant (2,548,245 samples, 0.01%)[unknown] (2,548,245 samples, 0.01%)core::ptr::drop_in_place<pgdog::frontend::router::parser::command::Command> (2,548,245 samples, 0.01%)<hashbrown::map::HashMap<K,V,S,A> as core::clone::Clone>::clone (5,072,999 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::error::Error> (8,622,142 samples, 0.04%)hashbrown::map::HashMap<K,V,S,A>::remove (4,847,213 samples, 0.02%)hashbrown::map::HashMap<K,V,S,A>::remove_entry (4,847,213 samples, 0.02%)hashbrown::raw::RawTable<T,A>::remove_entry (4,847,213 samples, 0.02%)hashbrown::raw::RawTable<T,A>::remove (4,847,213 samples, 0.02%)hashbrown::raw::RawTable<T,A>::erase_no_drop (4,847,213 samples, 0.02%)hashbrown::raw::RawTableInner::erase (4,847,213 samples, 0.02%)hashbrown::control::bitmask::BitMask::leading_zeros (4,847,213 samples, 0.02%)core::num::<impl u16>::leading_zeros (4,847,213 samples, 0.02%)pgdog::backend::pool::cleanup::Cleanup::new (7,119,614 samples, 0.03%)[unknown] (29,734,016 samples, 0.13%)pgdog::config::config (4,072,048 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::pool::guard::Guard> (3,347,321 samples, 0.01%)<pgdog::backend::pool::guard::Guard as core::ops::drop::Drop>::drop (3,347,321 samples, 0.01%)pgdog::backend::pool::guard::Guard::cleanup (3,347,321 samples, 0.01%)[libc.so.6] (11,828,109 samples, 0.05%)[libm.so.6] (13,740,782 samples, 0.06%)_rjem_malloc (4,277,968 samples, 0.02%)imalloc_fastpath (4,277,968 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::error::Error> (5,274,660 samples, 0.02%)std::f64::<impl f64>::powf (72,754,801 samples, 0.31%)pow (39,673,464 samples, 0.17%)std::sys::pal::unix::time::Timespec::now (4,551,945 samples, 0.02%)__vdso_clock_gettime (20,981,380 samples, 0.09%)tokio::runtime::scheduler::multi_thread::stats::Stats::end_processing_scheduled_tasks (114,998,694 samples, 0.49%)std::time::Instant::now (29,743,684 samples, 0.13%)std::sys::pal::unix::time::Instant::now (29,743,684 samples, 0.13%)std::sys::pal::unix::time::Timespec::now (29,743,684 samples, 0.13%)clock_gettime (29,743,684 samples, 0.13%)tokio::io::util::buf_writer::BufWriter<W>::flush_buf (8,762,304 samples, 0.04%)tokio::runtime::scheduler::multi_thread::stats::Stats::start_processing_scheduled_tasks (24,959,906 samples, 0.11%)std::time::Instant::now (24,959,906 samples, 0.11%)std::sys::pal::unix::time::Instant::now (24,959,906 samples, 0.11%)std::sys::pal::unix::time::Timespec::now (24,959,906 samples, 0.11%)clock_gettime (24,959,906 samples, 0.11%)__vdso_clock_gettime (20,048,913 samples, 0.08%)<alloc::sync::Arc<T,A> as core::ops::deref::Deref>::deref (9,515,536 samples, 0.04%)alloc::sync::Arc<T,A>::inner (9,515,536 samples, 0.04%)core::ptr::non_null::NonNull<T>::as_ref (9,515,536 samples, 0.04%)tokio::runtime::scheduler::multi_thread::stats::Stats::end_processing_scheduled_tasks (3,678,929 samples, 0.02%)std::f64::<impl f64>::powf (3,678,929 samples, 0.02%)pow (3,678,929 samples, 0.02%)[libc.so.6] (3,678,929 samples, 0.02%)tokio::runtime::driver::Driver::park_timeout (3,609,056 samples, 0.02%)tokio::runtime::driver::TimeDriver::park_timeout (3,609,056 samples, 0.02%)tokio::runtime::time::Driver::park_timeout (3,609,056 samples, 0.02%)core::num::<impl u64>::saturating_sub (2,486,175 samples, 0.01%)tokio::runtime::io::driver::Driver::turn (4,049,806 samples, 0.02%)mio::poll::Poll::poll (4,049,806 samples, 0.02%)mio::sys::unix::selector::Selector::select (4,049,806 samples, 0.02%)epoll_wait (4,049,806 samples, 0.02%)[libc.so.6] (4,049,806 samples, 0.02%)[libc.so.6] (4,049,806 samples, 0.02%)[libc.so.6] (4,049,806 samples, 0.02%)entry_SYSCALL_64_after_hwframe (4,049,806 samples, 0.02%)do_syscall_64 (4,049,806 samples, 0.02%)tokio::runtime::scheduler::multi_thread::worker::Context::maintenance (37,088,228 samples, 0.16%)tokio::runtime::scheduler::multi_thread::worker::Context::park_timeout (16,240,870 samples, 0.07%)tokio::runtime::scheduler::multi_thread::park::Parker::park_timeout (16,240,870 samples, 0.07%)tokio::runtime::time::Driver::park_internal (12,631,814 samples, 0.05%)tokio::runtime::time::source::TimeSource::now (6,095,833 samples, 0.03%)tokio::time::clock::Clock::now (6,095,833 samples, 0.03%)tokio::time::clock::now (6,095,833 samples, 0.03%)std::time::Instant::now (6,095,833 samples, 0.03%)std::sys::pal::unix::time::Instant::now (6,095,833 samples, 0.03%)std::sys::pal::unix::time::Timespec::now (6,095,833 samples, 0.03%)clock_gettime (6,095,833 samples, 0.03%)__vdso_clock_gettime (6,095,833 samples, 0.03%)core::cell::RefCell<T>::borrow_mut (12,310,410 samples, 0.05%)core::cell::RefCell<T>::try_borrow_mut (12,310,410 samples, 0.05%)core::cell::BorrowRefMut::new (12,310,410 samples, 0.05%)tokio::runtime::scheduler::defer::Defer::wake (4,940,647 samples, 0.02%)core::cell::RefCell<T>::borrow_mut (4,940,647 samples, 0.02%)core::cell::RefCell<T>::try_borrow_mut (4,940,647 samples, 0.02%)core::cell::BorrowRefMut::new (4,940,647 samples, 0.02%)core::sync::atomic::AtomicI32::load (5,721,698 samples, 0.02%)core::sync::atomic::atomic_load (5,721,698 samples, 0.02%)parking_lot_core::parking_lot::park::_{{closure}} (10,162,484 samples, 0.04%)<parking_lot_core::thread_parker::imp::ThreadParker as parking_lot_core::thread_parker::ThreadParkerT>::park (10,162,484 samples, 0.04%)parking_lot_core::thread_parker::imp::ThreadParker::futex_wait (4,440,786 samples, 0.02%)syscall (4,440,786 samples, 0.02%)entry_SYSCALL_64_after_hwframe (4,440,786 samples, 0.02%)do_syscall_64 (4,440,786 samples, 0.02%)__x64_sys_futex (4,440,786 samples, 0.02%)do_futex (4,440,786 samples, 0.02%)futex_wait (4,440,786 samples, 0.02%)__futex_wait (4,440,786 samples, 0.02%)futex_wait_queue (4,440,786 samples, 0.02%)schedule (4,440,786 samples, 0.02%)__schedule (4,440,786 samples, 0.02%)__perf_event_task_sched_out (4,440,786 samples, 0.02%)ctx_sched_out (4,440,786 samples, 0.02%)tokio::runtime::scheduler::multi_thread::park::Inner::park_condvar (10,380,667 samples, 0.04%)tokio::loom::std::parking_lot::Condvar::wait (10,380,667 samples, 0.04%)parking_lot::condvar::Condvar::wait (10,380,667 samples, 0.04%)parking_lot::condvar::Condvar::wait_until_internal (10,380,667 samples, 0.04%)parking_lot_core::parking_lot::park (10,380,667 samples, 0.04%)parking_lot_core::parking_lot::with_thread_data (10,380,667 samples, 0.04%)core::sync::atomic::AtomicUsize::swap (16,035,839 samples, 0.07%)core::sync::atomic::atomic_swap (16,035,839 samples, 0.07%)core::ptr::drop_in_place<tokio::loom::std::parking_lot::MutexGuard<alloc::vec::Vec<std::process::Child>>> (6,650,931 samples, 0.03%)core::ptr::drop_in_place<lock_api::mutex::MutexGuard<parking_lot::raw_mutex::RawMutex,alloc::vec::Vec<std::process::Child>>> (6,650,931 samples, 0.03%)<lock_api::mutex::MutexGuard<R,T> as core::ops::drop::Drop>::drop (6,650,931 samples, 0.03%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::unlock (6,650,931 samples, 0.03%)core::sync::atomic::AtomicU8::compare_exchange (6,650,931 samples, 0.03%)core::sync::atomic::atomic_compare_exchange (6,650,931 samples, 0.03%)core::ptr::drop_in_place<tokio::loom::std::parking_lot::MutexGuard<core::option::Option<tokio::sync::watch::Receiver<()>>>> (5,391,782 samples, 0.02%)core::ptr::drop_in_place<lock_api::mutex::MutexGuard<parking_lot::raw_mutex::RawMutex,core::option::Option<tokio::sync::watch::Receiver<()>>>> (5,391,782 samples, 0.02%)<lock_api::mutex::MutexGuard<R,T> as core::ops::drop::Drop>::drop (5,391,782 samples, 0.02%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::unlock (5,391,782 samples, 0.02%)tokio::process::imp::GlobalOrphanQueue::reap_orphans (38,867,441 samples, 0.16%)tokio::process::imp::orphan::OrphanQueueImpl<T>::reap_orphans (31,044,646 samples, 0.13%)tokio::loom::std::parking_lot::Mutex<T>::try_lock (19,001,933 samples, 0.08%)lock_api::mutex::Mutex<R,T>::try_lock (19,001,933 samples, 0.08%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::try_lock (19,001,933 samples, 0.08%)<mio::event::events::Iter as core::iter::traits::iterator::Iterator>::next (4,624,906 samples, 0.02%)core::slice::<impl [T]>::get (4,624,906 samples, 0.02%)<usize as core::slice::index::SliceIndex<[T]>>::get (4,624,906 samples, 0.02%)core::result::Result<T,E>::map (9,044,696 samples, 0.04%)mio::sys::unix::selector::Selector::select::_{{closure}} (9,044,696 samples, 0.04%)alloc::vec::Vec<T,A>::set_len (9,044,696 samples, 0.04%)__put_user_nocheck_4 (3,550,135 samples, 0.01%)__put_user_nocheck_8 (9,055,084 samples, 0.04%)asm_sysvec_apic_timer_interrupt (5,639,238 samples, 0.02%)sysvec_apic_timer_interrupt (5,639,238 samples, 0.02%)__sysvec_apic_timer_interrupt (5,628,504 samples, 0.02%)hrtimer_interrupt (5,628,488 samples, 0.02%)__hrtimer_run_queues (5,628,488 samples, 0.02%)tick_nohz_handler (5,628,488 samples, 0.02%)update_process_times (5,628,488 samples, 0.02%)smp_call_function_single_async (5,627,227 samples, 0.02%)generic_exec_single (5,627,227 samples, 0.02%)default_send_IPI_single_phys (5,627,227 samples, 0.02%)ep_done_scan (9,022,541 samples, 0.04%)__pm_relax (4,028,740 samples, 0.02%)fput (4,059,124 samples, 0.02%)ep_item_poll.isra.0 (4,061,394 samples, 0.02%)fput (4,987,613 samples, 0.02%)mutex_unlock (2,771,470 samples, 0.01%)hrtimer_setup_sleeper_on_stack (5,083,513 samples, 0.02%)__hrtimer_init (5,083,513 samples, 0.02%)hrtimer_sleeper_start_expires (4,523,531 samples, 0.02%)hrtimer_start_range_ns (3,520,831 samples, 0.01%)asm_sysvec_apic_timer_interrupt (3,520,831 samples, 0.01%)sysvec_apic_timer_interrupt (3,520,831 samples, 0.01%)__sysvec_apic_timer_interrupt (3,520,831 samples, 0.01%)hrtimer_interrupt (3,520,831 samples, 0.01%)__hrtimer_run_queues (3,520,831 samples, 0.01%)tick_nohz_handler (3,520,831 samples, 0.01%)update_process_times (3,520,831 samples, 0.01%)sched_tick (3,520,831 samples, 0.01%)task_tick_fair (3,520,831 samples, 0.01%)update_curr (3,520,831 samples, 0.01%)__rcu_read_lock (2,571,337 samples, 0.01%)_raw_spin_lock (20,090,225 samples, 0.08%)__pmu_ctx_sched_out (214,249,891 samples, 0.90%)group_sched_out (172,261,971 samples, 0.73%)event_sched_out (156,982,236 samples, 0.66%)perf_ibs_del (148,286,294 samples, 0.63%)perf_ibs_stop (130,616,322 samples, 0.55%)native_read_msr (68,707,963 samples, 0.29%)ctx_sched_out (364,153,733 samples, 1.54%)local_clock (83,585,947 samples, 0.35%)local_clock_noinstr (62,580,850 samples, 0.26%)native_sched_clock (42,865,963 samples, 0.18%)perf_ctx_disable (45,563,039 samples, 0.19%)perf_pmu_nop_void (3,047,146 samples, 0.01%)__perf_event_task_sched_out (530,900,042 samples, 2.24%)_..perf_ctx_sched_task_cb (26,441,400 samples, 0.11%)pick_task_fair (3,925,024 samples, 0.02%)__rcu_read_unlock (10,400,202 samples, 0.04%)__bitmap_and (4,823,604 samples, 0.02%)sched_balance_rq (7,609,416 samples, 0.03%)_raw_spin_rq_lock_irqsave (2,785,812 samples, 0.01%)raw_spin_rq_lock_nested (2,785,812 samples, 0.01%)_raw_spin_lock (2,785,812 samples, 0.01%)native_queued_spin_lock_slowpath (2,785,812 samples, 0.01%)sched_balance_update_blocked_averages (3,288,215 samples, 0.01%)update_rq_clock (3,183,997 samples, 0.01%)sched_clock_cpu (3,183,997 samples, 0.01%)sched_clock (3,183,997 samples, 0.01%)native_sched_clock (3,183,997 samples, 0.01%)pick_next_task_fair (164,500,075 samples, 0.69%)sched_balance_newidle (134,618,367 samples, 0.57%)srso_alias_safe_ret (4,398,962 samples, 0.02%)pick_task_idle (3,882,696 samples, 0.02%)put_prev_task_fair (108,629,485 samples, 0.46%)put_prev_entity (37,259,084 samples, 0.16%)__rcu_read_unlock (5,265,781 samples, 0.02%)set_next_task_idle (89,140,299 samples, 0.38%)__update_idle_core (71,724,470 samples, 0.30%)__rcu_read_lock (10,755,181 samples, 0.05%)__pick_next_task (500,548,047 samples, 2.11%)_..srso_alias_return_thunk (14,039,022 samples, 0.06%)srso_alias_safe_ret (14,039,022 samples, 0.06%)dequeue_task (3,184,117 samples, 0.01%)srso_alias_return_thunk (15,395,677 samples, 0.06%)srso_alias_safe_ret (15,395,677 samples, 0.06%)srso_alias_safe_ret (5,823,144 samples, 0.02%)update_cfs_group (44,063,197 samples, 0.19%)__calc_delta.constprop.0 (14,832,102 samples, 0.06%)__cgroup_account_cputime (9,976,134 samples, 0.04%)cpuacct_charge (18,851,434 samples, 0.08%)dl_server_update (19,962,268 samples, 0.08%)dl_scaled_delta_exec (21,793,185 samples, 0.09%)srso_alias_return_thunk (4,880,569 samples, 0.02%)srso_alias_safe_ret (4,880,569 samples, 0.02%)update_curr_dl_se (53,245,256 samples, 0.22%)start_dl_timer (4,530,283 samples, 0.02%)hrtimer_start_range_ns (4,530,283 samples, 0.02%)get_nohz_timer_target (4,530,283 samples, 0.02%)update_curr_se (13,744,643 samples, 0.06%)update_curr (335,598,110 samples, 1.42%)update_min_vruntime (23,509,408 samples, 0.10%)__calc_delta.constprop.0 (3,115,165 samples, 0.01%)update_entity_lag (148,640,503 samples, 0.63%)avg_vruntime (41,270,199 samples, 0.17%)__update_load_avg_cfs_rq (48,082,812 samples, 0.20%)__update_load_avg_se (53,328,281 samples, 0.23%)update_load_avg (305,017,100 samples, 1.29%)srso_alias_return_thunk (3,366,196 samples, 0.01%)srso_alias_safe_ret (3,366,196 samples, 0.01%)update_min_vruntime (9,836,285 samples, 0.04%)dequeue_entity (1,230,901,636 samples, 5.20%)dequeu..vruntime_eligible (33,088,777 samples, 0.14%)__dequeue_dl_entity (40,674,238 samples, 0.17%)_raw_spin_unlock_irqrestore (4,006,441 samples, 0.02%)_raw_spin_lock_irqsave (4,092,734 samples, 0.02%)enqueue_hrtimer (4,614,811 samples, 0.02%)get_nohz_timer_target (19,392,587 samples, 0.08%)ktime_get (66,934,513 samples, 0.28%)read_tsc (45,643,174 samples, 0.19%)rb_insert_color (23,255,921 samples, 0.10%)hrtimer_start_range_ns (245,319,370 samples, 1.04%)timerqueue_add (78,807,855 samples, 0.33%)srso_alias_safe_ret (3,287,105 samples, 0.01%)hrtimer_try_to_cancel (24,550,473 samples, 0.10%)__remove_hrtimer (62,325,792 samples, 0.26%)timerqueue_del (39,621,948 samples, 0.17%)rb_erase (31,418,260 samples, 0.13%)_raw_spin_lock_irqsave (9,067,384 samples, 0.04%)_raw_spin_unlock_irqrestore (3,708,746 samples, 0.02%)hrtimer_try_to_cancel.part.0 (128,423,501 samples, 0.54%)srso_alias_return_thunk (4,681,843 samples, 0.02%)srso_alias_safe_ret (4,681,843 samples, 0.02%)hrtimer_try_to_cancel (4,444,330 samples, 0.02%)hrtimer_active (4,444,330 samples, 0.02%)dequeue_task_fair (2,000,553,159 samples, 8.45%)dequeue_task..dequeue_entities (1,975,065,737 samples, 8.34%)dequeue_enti..dl_server_stop (520,430,865 samples, 2.20%)d..task_non_contending (42,725,930 samples, 0.18%)psi_account_irqtime (5,181,045 samples, 0.02%)sched_clock_cpu (5,181,045 samples, 0.02%)sched_clock (5,181,045 samples, 0.02%)native_sched_clock (5,181,045 samples, 0.02%)finish_task_switch.isra.0 (11,875,328 samples, 0.05%)asm_sysvec_apic_timer_interrupt (11,875,328 samples, 0.05%)sysvec_apic_timer_interrupt (11,875,328 samples, 0.05%)__sysvec_apic_timer_interrupt (9,613,409 samples, 0.04%)hrtimer_interrupt (9,613,409 samples, 0.04%)__hrtimer_run_queues (9,613,409 samples, 0.04%)tick_nohz_handler (9,613,409 samples, 0.04%)update_process_times (9,613,409 samples, 0.04%)sched_tick (9,613,409 samples, 0.04%)update_rq_clock (4,432,364 samples, 0.02%)record_times (61,964,047 samples, 0.26%)sched_clock_cpu (73,163,789 samples, 0.31%)sched_clock (73,163,789 samples, 0.31%)native_sched_clock (64,585,155 samples, 0.27%)srso_alias_return_thunk (12,097,298 samples, 0.05%)srso_alias_safe_ret (12,097,298 samples, 0.05%)psi_account_irqtime (506,544,815 samples, 2.14%)p..srso_alias_safe_ret (16,425,260 samples, 0.07%)psi_flags_change (11,922,916 samples, 0.05%)record_times (24,249,746 samples, 0.10%)native_sched_clock (171,535,380 samples, 0.72%)sched_clock_cpu (206,542,701 samples, 0.87%)sched_clock (176,664,074 samples, 0.75%)sched_clock_noinstr (5,128,694 samples, 0.02%)srso_alias_return_thunk (5,238,830 samples, 0.02%)srso_alias_safe_ret (5,238,830 samples, 0.02%)psi_group_change (512,581,945 samples, 2.16%)p..srso_alias_safe_ret (19,437,789 samples, 0.08%)psi_task_switch (622,558,238 samples, 2.63%)ps..srso_alias_return_thunk (5,436,008 samples, 0.02%)srso_alias_return_thunk (4,058,301 samples, 0.02%)srso_alias_safe_ret (4,058,301 samples, 0.02%)schedule_hrtimeout_range (4,354,235,154 samples, 18.38%)schedule_hrtimeout_rangeschedule (4,341,107,263 samples, 18.33%)schedule__schedule (4,334,540,121 samples, 18.30%)__scheduleupdate_rq_clock (11,243,051 samples, 0.05%)__x64_sys_epoll_wait (4,422,351,974 samples, 18.67%)__x64_sys_epoll_waitdo_epoll_wait (4,411,256,039 samples, 18.62%)do_epoll_waitselect_estimate_accuracy (4,305,473 samples, 0.02%)ktime_get_ts64 (4,305,473 samples, 0.02%)read_tsc (4,305,473 samples, 0.02%)__get_user_8 (24,316,028 samples, 0.10%)__rseq_handle_notify_resume (70,681,776 samples, 0.30%)__put_user_8 (12,478,569 samples, 0.05%)arch_exit_to_user_mode_prepare.isra.0 (45,038,133 samples, 0.19%)switch_fpu_return (19,925,227 samples, 0.08%)restore_fpregs_from_fpstate (7,387,484 samples, 0.03%)blkcg_maybe_throttle_current (4,542,251 samples, 0.02%)srso_alias_return_thunk (5,546,442 samples, 0.02%)srso_alias_safe_ret (5,546,442 samples, 0.02%)entry_SYSCALL_64_after_hwframe (4,602,643,753 samples, 19.43%)entry_SYSCALL_64_after_hwframedo_syscall_64 (4,591,709,350 samples, 19.39%)do_syscall_64syscall_exit_to_user_mode (141,809,515 samples, 0.60%)syscall_exit_to_user_mode_prepare (3,366,063 samples, 0.01%)entry_SYSRETQ_unsafe_stack (5,540,578 samples, 0.02%)[libc.so.6] (4,656,693,329 samples, 19.66%)[libc.so.6]syscall_return_via_sysret (31,172,392 samples, 0.13%)[libc.so.6] (4,728,441,260 samples, 19.96%)[libc.so.6]mio::poll::Poll::poll (4,778,913,009 samples, 20.18%)mio::poll::Poll::pollmio::sys::unix::selector::Selector::select (4,778,913,009 samples, 20.18%)mio::sys::unix::selector::Select..epoll_wait (4,766,715,828 samples, 20.12%)epoll_wait[libc.so.6] (4,743,859,598 samples, 20.03%)[libc.so.6]__vdso_clock_gettime (11,158,537 samples, 0.05%)entry_SYSCALL_64 (11,158,537 samples, 0.05%)mio::event::event::Event::is_readable (5,299,542 samples, 0.02%)mio::sys::unix::selector::event::is_readable (5,299,542 samples, 0.02%)tokio::io::ready::Ready::from_mio (19,207,566 samples, 0.08%)mio::event::event::Event::is_write_closed (9,046,331 samples, 0.04%)mio::sys::unix::selector::event::is_write_closed (9,046,331 samples, 0.04%)tokio::runtime::io::scheduled_io::ScheduledIo::set_readiness (17,892,805 samples, 0.08%)core::sync::atomic::AtomicUsize::fetch_update (17,892,805 samples, 0.08%)tokio::runtime::io::scheduled_io::ScheduledIo::set_readiness::_{{closure}} (17,892,805 samples, 0.08%)tokio::util::bit::Pack::pack (17,892,805 samples, 0.08%)core::mem::drop (13,727,068 samples, 0.06%)core::ptr::drop_in_place<tokio::loom::std::parking_lot::MutexGuard<tokio::runtime::io::scheduled_io::Waiters>> (13,727,068 samples, 0.06%)core::ptr::drop_in_place<lock_api::mutex::MutexGuard<parking_lot::raw_mutex::RawMutex,tokio::runtime::io::scheduled_io::Waiters>> (13,727,068 samples, 0.06%)<lock_api::mutex::MutexGuard<R,T> as core::ops::drop::Drop>::drop (13,727,068 samples, 0.06%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::unlock (13,727,068 samples, 0.06%)core::sync::atomic::AtomicU8::compare_exchange (9,761,144 samples, 0.04%)core::sync::atomic::atomic_compare_exchange (9,761,144 samples, 0.04%)tokio::io::ready::Ready::is_readable (6,339,587 samples, 0.03%)asm_sysvec_apic_timer_interrupt (6,339,587 samples, 0.03%)sysvec_apic_timer_interrupt (6,339,587 samples, 0.03%)__irq_exit_rcu (6,339,587 samples, 0.03%)handle_softirqs (6,339,587 samples, 0.03%)sched_balance_softirq (6,339,587 samples, 0.03%)sched_balance_update_blocked_averages (6,339,587 samples, 0.03%)__update_load_avg_cfs_rq (6,339,587 samples, 0.03%)tokio::util::wake_list::WakeList::push (10,166,611 samples, 0.04%)tokio::runtime::task::harness::<impl tokio::runtime::task::raw::RawTask>::drop_reference (7,938,745 samples, 0.03%)tokio::runtime::task::state::State::ref_dec (7,938,745 samples, 0.03%)core::option::Option<T>::as_mut (4,367,613 samples, 0.02%)core::ptr::drop_in_place<core::cell::RefMut<core::option::Option<alloc::boxed::Box<tokio::runtime::scheduler::multi_thread::worker::Core>>>> (3,848,910 samples, 0.02%)core::ptr::drop_in_place<core::cell::BorrowRefMut> (3,848,910 samples, 0.02%)<core::cell::BorrowRefMut as core::ops::drop::Drop>::drop (3,848,910 samples, 0.02%)core::cell::Cell<T>::set (3,848,910 samples, 0.02%)core::cell::Cell<T>::replace (3,848,910 samples, 0.02%)core::mem::replace (3,848,910 samples, 0.02%)core::ptr::write (3,848,910 samples, 0.02%)tokio::runtime::scheduler::multi_thread::worker::<impl tokio::runtime::scheduler::multi_thread::handle::Handle>::ptr_eq (7,727,666 samples, 0.03%)tokio::runtime::scheduler::multi_thread::worker::<impl tokio::runtime::scheduler::multi_thread::handle::Handle>::schedule_task (33,234,733 samples, 0.14%)tokio::runtime::scheduler::multi_thread::worker::with_current (27,926,022 samples, 0.12%)tokio::runtime::context::with_scheduler (27,926,022 samples, 0.12%)std::thread::local::LocalKey<T>::try_with (27,926,022 samples, 0.12%)tokio::runtime::context::with_scheduler::_{{closure}} (27,926,022 samples, 0.12%)tokio::runtime::context::scoped::Scoped<T>::with (27,926,022 samples, 0.12%)tokio::runtime::scheduler::multi_thread::worker::with_current::_{{closure}} (27,926,022 samples, 0.12%)tokio::runtime::scheduler::multi_thread::worker::_<impl tokio::runtime::scheduler::multi_thread::handle::Handle>::schedule_task::_{{closure}} (27,926,022 samples, 0.12%)tokio::runtime::scheduler::multi_thread::worker::<impl tokio::runtime::scheduler::multi_thread::handle::Handle>::schedule_local (8,634,512 samples, 0.04%)core::option::Option<T>::take (4,292,796 samples, 0.02%)core::mem::replace (4,292,796 samples, 0.02%)core::ptr::write (4,292,796 samples, 0.02%)tokio::runtime::scheduler::multi_thread::worker::<impl tokio::runtime::task::Schedule for alloc::sync::Arc<tokio::runtime::scheduler::multi_thread::handle::Handle>>::schedule (4,996,887 samples, 0.02%)<alloc::sync::Arc<T,A> as core::ops::deref::Deref>::deref (4,996,887 samples, 0.02%)tokio::runtime::task::raw::RawTask::schedule (47,547,855 samples, 0.20%)tokio::runtime::task::raw::schedule (14,313,122 samples, 0.06%)core::sync::atomic::AtomicUsize::compare_exchange (4,924,950 samples, 0.02%)core::sync::atomic::atomic_compare_exchange (4,924,950 samples, 0.02%)tokio::runtime::io::driver::Driver::turn (4,983,515,076 samples, 21.04%)tokio::runtime::io::driver::Drive..tokio::runtime::io::scheduled_io::ScheduledIo::wake (158,151,537 samples, 0.67%)tokio::util::wake_list::WakeList::wake_all (123,522,919 samples, 0.52%)core::task::wake::Waker::wake (119,088,009 samples, 0.50%)tokio::runtime::task::waker::wake_by_val (113,040,449 samples, 0.48%)tokio::runtime::task::harness::<impl tokio::runtime::task::raw::RawTask>::wake_by_val (113,040,449 samples, 0.48%)tokio::runtime::task::state::State::transition_to_notified_by_val (54,938,880 samples, 0.23%)tokio::runtime::task::state::State::fetch_update_action (54,938,880 samples, 0.23%)tokio::runtime::task::state::State::load (50,013,930 samples, 0.21%)core::sync::atomic::AtomicUsize::load (50,013,930 samples, 0.21%)core::sync::atomic::atomic_load (50,013,930 samples, 0.21%)tokio::runtime::signal::Driver::process (12,889,066 samples, 0.05%)tokio::runtime::io::driver::signal::<impl tokio::runtime::io::driver::Driver>::consume_signal_ready (4,845,966 samples, 0.02%)core::mem::drop (7,644,325 samples, 0.03%)core::ptr::drop_in_place<tokio::loom::std::parking_lot::MutexGuard<tokio::runtime::time::wheel::Wheel>> (7,644,325 samples, 0.03%)core::ptr::drop_in_place<lock_api::mutex::MutexGuard<parking_lot::raw_mutex::RawMutex,tokio::runtime::time::wheel::Wheel>> (7,644,325 samples, 0.03%)<lock_api::mutex::MutexGuard<R,T> as core::ops::drop::Drop>::drop (7,644,325 samples, 0.03%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::unlock (7,644,325 samples, 0.03%)tokio::runtime::time::ShardedWheel::lock_sharded_wheel (7,729,869 samples, 0.03%)tokio::runtime::time::wheel::Wheel::next_expiration (4,974,576 samples, 0.02%)tokio::runtime::time::wheel::level::Level::next_expiration (4,974,576 samples, 0.02%)tokio::runtime::time::wheel::level::level_range (4,974,576 samples, 0.02%)tokio::runtime::time::wheel::Wheel::poll (10,225,521 samples, 0.04%)tokio::util::linked_list::LinkedList<L,<L as tokio::util::linked_list::Link>::Target>::pop_back (5,250,945 samples, 0.02%)<core::option::Option<T> as core::ops::try_trait::Try>::branch (5,250,945 samples, 0.02%)<core::iter::adapters::filter_map::FilterMap<I,F> as core::iter::traits::iterator::Iterator>::fold (37,865,798 samples, 0.16%)core::iter::traits::iterator::Iterator::fold (37,865,798 samples, 0.16%)core::iter::adapters::filter_map::filter_map_fold::_{{closure}} (37,865,798 samples, 0.16%)tokio::runtime::time::_<impl tokio::runtime::time::handle::Handle>::process_at_time::_{{closure}} (33,155,805 samples, 0.14%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::process_at_sharded_time (29,208,771 samples, 0.12%)tokio::runtime::time::wheel::Wheel::poll_at (3,609,056 samples, 0.02%)tokio::runtime::time::wheel::Wheel::next_expiration (3,609,056 samples, 0.02%)tokio::runtime::time::wheel::level::Level::next_expiration (3,609,056 samples, 0.02%)tokio::runtime::time::wheel::level::level_range (3,609,056 samples, 0.02%)core::iter::range::<impl core::iter::traits::iterator::Iterator for core::ops::range::Range<A>>::next (4,368,520 samples, 0.02%)<core::ops::range::Range<T> as core::iter::range::RangeIteratorImpl>::spec_next (4,368,520 samples, 0.02%)core::mem::drop (3,738,103 samples, 0.02%)core::ptr::drop_in_place<tokio::loom::std::parking_lot::RwLockReadGuard<tokio::runtime::time::ShardedWheel>> (3,738,103 samples, 0.02%)core::ptr::drop_in_place<lock_api::rwlock::RwLockReadGuard<parking_lot::raw_rwlock::RawRwLock,tokio::runtime::time::ShardedWheel>> (3,738,103 samples, 0.02%)<lock_api::rwlock::RwLockReadGuard<R,T> as core::ops::drop::Drop>::drop (3,738,103 samples, 0.02%)<parking_lot::raw_rwlock::RawRwLock as lock_api::rwlock::RawRwLock>::unlock_shared (3,738,103 samples, 0.02%)tokio::runtime::time::ShardedWheel::lock_sharded_wheel (5,713,775 samples, 0.02%)tokio::runtime::time::wheel::level::Level::next_occupied_slot (12,997,649 samples, 0.05%)tokio::runtime::time::wheel::level::slot_range (4,383,708 samples, 0.02%)core::num::<impl usize>::pow (4,383,708 samples, 0.02%)tokio::runtime::time::wheel::level::Level::next_expiration (30,197,438 samples, 0.13%)tokio::runtime::time::wheel::level::level_range (4,129,161 samples, 0.02%)tokio::runtime::time::wheel::level::slot_range (4,129,161 samples, 0.02%)core::num::<impl usize>::pow (4,129,161 samples, 0.02%)tokio::runtime::time::wheel::Wheel::poll (38,273,299 samples, 0.16%)tokio::runtime::time::wheel::Wheel::next_expiration (38,273,299 samples, 0.16%)tokio::util::linked_list::LinkedList<L,<L as tokio::util::linked_list::Link>::Target>::is_empty (3,896,862 samples, 0.02%)core::option::Option<T>::map (4,910,857 samples, 0.02%)tokio::runtime::time::wheel::Wheel::poll_at (15,262,653 samples, 0.06%)tokio::runtime::time::wheel::Wheel::next_expiration (5,239,124 samples, 0.02%)tokio::runtime::time::wheel::level::Level::next_expiration (5,239,124 samples, 0.02%)tokio::runtime::time::wheel::level::Level::next_occupied_slot (5,239,124 samples, 0.02%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::process_at_time (116,256,145 samples, 0.49%)core::iter::traits::iterator::Iterator::min (116,256,145 samples, 0.49%)core::iter::traits::iterator::Iterator::min_by (116,256,145 samples, 0.49%)core::iter::traits::iterator::Iterator::reduce (116,256,145 samples, 0.49%)<core::iter::adapters::filter_map::FilterMap<I,F> as core::iter::traits::iterator::Iterator>::next (78,390,347 samples, 0.33%)core::iter::traits::iterator::Iterator::find_map (78,390,347 samples, 0.33%)core::iter::traits::iterator::Iterator::try_fold (78,390,347 samples, 0.33%)core::iter::traits::iterator::Iterator::find_map::check::_{{closure}} (67,400,906 samples, 0.28%)core::ops::function::impls::<impl core::ops::function::FnMut<A> for &mut F>::call_mut (67,400,906 samples, 0.28%)tokio::runtime::time::_<impl tokio::runtime::time::handle::Handle>::process_at_time::_{{closure}} (67,400,906 samples, 0.28%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::process_at_sharded_time (67,400,906 samples, 0.28%)tokio::util::wake_list::WakeList::new (4,413,076 samples, 0.02%)core::time::Duration::as_millis (4,092,173 samples, 0.02%)core::result::Result<T,E>::ok (5,017,962 samples, 0.02%)tokio::runtime::time::source::TimeSource::instant_to_tick (18,469,119 samples, 0.08%)tokio::time::instant::Instant::saturating_duration_since (14,376,946 samples, 0.06%)std::time::Instant::duration_since (14,376,946 samples, 0.06%)std::time::Instant::checked_duration_since (14,376,946 samples, 0.06%)std::sys::pal::unix::time::Instant::checked_sub_instant (14,376,946 samples, 0.06%)std::sys::pal::unix::time::Timespec::sub_timespec (9,358,984 samples, 0.04%)clock_gettime (83,970,173 samples, 0.35%)__vdso_clock_gettime (65,847,407 samples, 0.28%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::process (227,692,438 samples, 0.96%)tokio::runtime::time::source::TimeSource::now (111,436,293 samples, 0.47%)tokio::time::clock::Clock::now (92,967,174 samples, 0.39%)tokio::time::clock::now (92,967,174 samples, 0.39%)std::time::Instant::now (92,967,174 samples, 0.39%)std::sys::pal::unix::time::Instant::now (92,967,174 samples, 0.39%)std::sys::pal::unix::time::Timespec::now (92,967,174 samples, 0.39%)core::result::Result<T,E>::unwrap (2,770,414 samples, 0.01%)tokio::runtime::time::entry::TimerEntry::reset (7,144,033 samples, 0.03%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::reregister (7,144,033 samples, 0.03%)tokio::runtime::time::handle::Handle::is_shutdown (7,144,033 samples, 0.03%)tokio::runtime::time::Inner::is_shutdown (7,144,033 samples, 0.03%)core::sync::atomic::AtomicBool::load (7,144,033 samples, 0.03%)core::sync::atomic::atomic_load (7,144,033 samples, 0.03%)__vdso_clock_gettime (4,082,175 samples, 0.02%)tokio::runtime::time::Driver::park_internal (5,300,970,659 samples, 22.38%)tokio::runtime::time::Driver::park_..tokio::runtime::time::source::TimeSource::now (13,505,120 samples, 0.06%)tokio::time::clock::Clock::now (13,487,351 samples, 0.06%)tokio::time::clock::now (13,487,351 samples, 0.06%)std::time::Instant::now (13,487,351 samples, 0.06%)std::sys::pal::unix::time::Instant::now (13,487,351 samples, 0.06%)std::sys::pal::unix::time::Timespec::now (13,487,351 samples, 0.06%)clock_gettime (13,487,351 samples, 0.06%)core::ptr::drop_in_place<pgdog::backend::pool::guard::Guard> (4,816,575 samples, 0.02%)<pgdog::backend::pool::guard::Guard as core::ops::drop::Drop>::drop (4,816,575 samples, 0.02%)pgdog::backend::pool::guard::Guard::cleanup (4,816,575 samples, 0.02%)pgdog::backend::pool::cleanup::Cleanup::needed (4,816,575 samples, 0.02%)alloc::vec::Vec<T,A>::is_empty (4,816,575 samples, 0.02%)tokio::runtime::scheduler::multi_thread::park::Parker::park (5,335,538,326 samples, 22.53%)tokio::runtime::scheduler::multi_thr..tokio::runtime::scheduler::multi_thread::park::Inner::park (5,335,538,326 samples, 22.53%)tokio::runtime::scheduler::multi_thr..tokio::runtime::scheduler::multi_thread::park::Inner::park_driver (5,325,157,659 samples, 22.48%)tokio::runtime::scheduler::multi_thr..tokio::sync::notify::Notified::poll_notified (3,241,604 samples, 0.01%)tokio::util::linked_list::LinkedList<L,<L as tokio::util::linked_list::Link>::Target>::push_front (3,241,604 samples, 0.01%)tokio::runtime::scheduler::multi_thread::worker::Context::park_timeout (5,370,847,672 samples, 22.68%)tokio::runtime::scheduler::multi_thr..tokio::runtime::scheduler::multi_thread::worker::Core::should_notify_others (11,998,307 samples, 0.05%)tokio::runtime::scheduler::multi_thread::queue::Local<T>::len (4,957,310 samples, 0.02%)tokio::runtime::scheduler::multi_thread::queue::Inner<T>::len (4,957,310 samples, 0.02%)core::sync::atomic::AtomicU32::load (4,957,310 samples, 0.02%)core::sync::atomic::atomic_load (4,957,310 samples, 0.02%)core::ptr::drop_in_place<tokio::loom::std::parking_lot::MutexGuard<tokio::runtime::scheduler::multi_thread::worker::Synced>> (6,346,851 samples, 0.03%)core::ptr::drop_in_place<lock_api::mutex::MutexGuard<parking_lot::raw_mutex::RawMutex,tokio::runtime::scheduler::multi_thread::worker::Synced>> (6,346,851 samples, 0.03%)<lock_api::mutex::MutexGuard<R,T> as core::ops::drop::Drop>::drop (6,346,851 samples, 0.03%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::unlock (6,346,851 samples, 0.03%)tokio::runtime::scheduler::multi_thread::worker::Core::maintenance (18,246,412 samples, 0.08%)tokio::runtime::scheduler::inject::shared::Shared<T>::is_closed (6,976,973 samples, 0.03%)core::iter::range::<impl core::iter::traits::iterator::Iterator for core::ops::range::Range<A>>::next (3,919,640 samples, 0.02%)<core::ops::range::Range<T> as core::iter::range::RangeIteratorImpl>::spec_next (3,919,640 samples, 0.02%)core::cmp::impls::<impl core::cmp::PartialOrd for usize>::lt (3,919,640 samples, 0.02%)tokio::runtime::scheduler::multi_thread::worker::Context::park (5,407,543,279 samples, 22.83%)tokio::runtime::scheduler::multi_thr..tokio::runtime::scheduler::multi_thread::worker::Core::transition_from_parked (18,449,195 samples, 0.08%)tokio::runtime::scheduler::multi_thread::idle::Idle::unpark_worker_by_id (18,449,195 samples, 0.08%)tokio::loom::std::parking_lot::Mutex<T>::lock (10,437,404 samples, 0.04%)lock_api::mutex::Mutex<R,T>::lock (10,437,404 samples, 0.04%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::lock (10,437,404 samples, 0.04%)core::sync::atomic::AtomicU8::compare_exchange_weak (5,922,149 samples, 0.03%)core::sync::atomic::atomic_compare_exchange_weak (5,922,149 samples, 0.03%)core::option::Option<T>::take (9,641,795 samples, 0.04%)core::mem::replace (9,641,795 samples, 0.04%)core::ptr::write (9,641,795 samples, 0.04%)tokio::runtime::scheduler::multi_thread::worker::Context::reset_lifo_enabled (6,550,135 samples, 0.03%)<pgdog::backend::server::Server as core::ops::drop::Drop>::drop::_{{closure}} (5,621,380 samples, 0.02%)tokio::io::util::buf_writer::BufWriter<W>::flush_buf (5,621,380 samples, 0.02%)<tokio::net::tcp::stream::TcpStream as tokio::io::async_write::AsyncWrite>::poll_write (5,621,380 samples, 0.02%)tokio::net::tcp::stream::TcpStream::poll_write_priv (5,621,380 samples, 0.02%)tokio::io::poll_evented::PollEvented<E>::poll_write (5,621,380 samples, 0.02%)<&mio::net::tcp::stream::TcpStream as std::io::Write>::write (5,621,380 samples, 0.02%)mio::io_source::IoSource<T>::do_io (5,621,380 samples, 0.02%)mio::sys::unix::selector::stateless_io_source::IoSourceState::do_io (5,621,380 samples, 0.02%)<&mio::net::tcp::stream::TcpStream as std::io::Write>::write::_{{closure}} (5,621,380 samples, 0.02%)<&std::net::tcp::TcpStream as std::io::Write>::write (5,621,380 samples, 0.02%)std::sys::net::connection::socket::TcpStream::write (5,621,380 samples, 0.02%)__send (5,621,380 samples, 0.02%)[libc.so.6] (5,621,380 samples, 0.02%)[libc.so.6] (5,621,380 samples, 0.02%)[libc.so.6] (5,621,380 samples, 0.02%)entry_SYSCALL_64_after_hwframe (5,621,380 samples, 0.02%)do_syscall_64 (5,621,380 samples, 0.02%)__x64_sys_sendto (5,621,380 samples, 0.02%)__sys_sendto (5,621,380 samples, 0.02%)tcp_sendmsg (5,621,380 samples, 0.02%)tcp_sendmsg_locked (5,621,380 samples, 0.02%)tcp_skb_entail (5,621,380 samples, 0.02%)ring::digest::BlockContext::finish (4,341,537 samples, 0.02%)GFp_sha256_block_data_order_ssse3 (4,341,537 samples, 0.02%)ring::hmac::Context::sign (4,344,128 samples, 0.02%)pgdog::auth::scram::server::Server::handle::_{{closure}} (4,344,351 samples, 0.02%)scram::server::ScramServer<P>::handle_client_first (4,344,351 samples, 0.02%)<pgdog::auth::scram::server::UserPassword as scram::server::AuthenticationProvider>::get_password_for (4,344,351 samples, 0.02%)scram::utils::hash_password (4,344,351 samples, 0.02%)ring::pbkdf2::derive (4,344,351 samples, 0.02%)ring::pbkdf2::derive_block (4,344,351 samples, 0.02%)ring::hmac::sign (4,344,335 samples, 0.02%)core::option::Option<&T>::cloned (17,901,068 samples, 0.08%)<core::task::wake::Waker as core::clone::Clone>::clone (17,901,068 samples, 0.08%)tokio::runtime::task::waker::clone_waker (17,901,068 samples, 0.08%)tokio::runtime::task::state::State::ref_inc (10,392,400 samples, 0.04%)core::sync::atomic::AtomicUsize::fetch_add (10,392,400 samples, 0.04%)core::sync::atomic::atomic_add (10,392,400 samples, 0.04%)asm_sysvec_apic_timer_interrupt (3,929,252 samples, 0.02%)sysvec_apic_timer_interrupt (3,929,252 samples, 0.02%)__irq_exit_rcu (3,929,252 samples, 0.02%)handle_softirqs (3,929,252 samples, 0.02%)rcu_core (3,929,252 samples, 0.02%)rcu_do_batch (3,929,252 samples, 0.02%)rcu_cblist_dequeue (3,929,252 samples, 0.02%)<tokio::sync::notify::Notified as core::future::future::Future>::poll (30,577,833 samples, 0.13%)tokio::sync::notify::Notified::poll_notified (30,577,833 samples, 0.13%)tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut (5,986,029 samples, 0.03%)tokio::sync::notify::Notified::poll_notified::_{{closure}} (5,986,029 samples, 0.03%)<core::task::wake::Waker as core::clone::Clone>::clone (5,986,029 samples, 0.03%)tokio::runtime::coop::poll_proceed (4,092,332 samples, 0.02%)tokio::runtime::context::budget (4,092,332 samples, 0.02%)std::thread::local::LocalKey<T>::try_with (4,092,332 samples, 0.02%)tokio::runtime::context::budget::_{{closure}} (4,092,332 samples, 0.02%)tokio::runtime::coop::poll_proceed::_{{closure}} (4,092,332 samples, 0.02%)tokio::runtime::coop::Budget::decrement (4,092,332 samples, 0.02%)tokio::runtime::time::entry::StateCell::poll (27,763,268 samples, 0.12%)tokio::sync::task::atomic_waker::AtomicWaker::register_by_ref (27,763,268 samples, 0.12%)tokio::sync::task::atomic_waker::AtomicWaker::do_register (27,763,268 samples, 0.12%)tokio::sync::task::atomic_waker::AtomicWaker::do_register::catch_unwind (6,717,301 samples, 0.03%)std::panic::catch_unwind (6,717,301 samples, 0.03%)std::panicking::try (6,717,301 samples, 0.03%)std::panicking::try::do_call (6,717,301 samples, 0.03%)<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once (6,717,301 samples, 0.03%)tokio::sync::task::atomic_waker::AtomicWaker::do_register::_{{closure}} (6,717,301 samples, 0.03%)core::mem::drop (6,717,301 samples, 0.03%)core::ptr::drop_in_place<core::option::Option<core::task::wake::Waker>> (6,717,301 samples, 0.03%)core::ptr::drop_in_place<core::task::wake::Waker> (6,717,301 samples, 0.03%)<core::task::wake::Waker as core::ops::drop::Drop>::drop (6,717,301 samples, 0.03%)tokio::runtime::task::waker::drop_waker (6,717,301 samples, 0.03%)tokio::runtime::task::harness::<impl tokio::runtime::task::raw::RawTask>::drop_reference (6,717,301 samples, 0.03%)tokio::runtime::task::state::State::ref_dec (6,717,301 samples, 0.03%)tokio::runtime::time::entry::TimerEntry::driver (8,292,104 samples, 0.04%)tokio::runtime::driver::Handle::time (8,292,104 samples, 0.04%)core::option::Option<T>::as_ref (8,292,104 samples, 0.04%)tokio::loom::std::parking_lot::RwLock<T>::read (3,995,457 samples, 0.02%)lock_api::rwlock::RwLock<R,T>::read (3,995,457 samples, 0.02%)<parking_lot::raw_rwlock::RawRwLock as lock_api::rwlock::RawRwLock>::lock_shared (3,995,457 samples, 0.02%)parking_lot::raw_rwlock::RawRwLock::try_lock_shared_fast (3,995,457 samples, 0.02%)core::slice::<impl [T]>::get_unchecked (3,619,413 samples, 0.02%)<usize as core::slice::index::SliceIndex<[T]>>::get_unchecked (3,619,413 samples, 0.02%)core::slice::index::get_noubcheck (3,619,413 samples, 0.02%)tokio::runtime::time::ShardedWheel::lock_sharded_wheel (17,329,206 samples, 0.07%)tokio::loom::std::parking_lot::Mutex<T>::lock (13,709,793 samples, 0.06%)lock_api::mutex::Mutex<R,T>::lock (13,709,793 samples, 0.06%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::lock (13,709,793 samples, 0.06%)tokio::runtime::time::wheel::level::slot_for (15,511,959 samples, 0.07%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::reregister (56,166,521 samples, 0.24%)tokio::runtime::time::wheel::Wheel::insert (32,495,933 samples, 0.14%)tokio::runtime::time::wheel::level::Level::add_entry (32,495,933 samples, 0.14%)tokio::util::linked_list::LinkedList<L,<L as tokio::util::linked_list::Link>::Target>::push_front (16,983,974 samples, 0.07%)<core::option::Option<T> as core::cmp::PartialEq>::eq (16,983,974 samples, 0.07%)tokio::runtime::time::entry::TimerEntry::inner (13,478,522 samples, 0.06%)tokio::runtime::time::entry::generate_shard_id (13,478,522 samples, 0.06%)tokio::runtime::context::with_scheduler (8,384,532 samples, 0.04%)std::thread::local::LocalKey<T>::try_with (8,384,532 samples, 0.04%)tokio::runtime::context::with_scheduler::_{{closure}} (8,384,532 samples, 0.04%)tokio::runtime::context::scoped::Scoped<T>::with (8,384,532 samples, 0.04%)tokio::runtime::time::entry::generate_shard_id::_{{closure}} (8,384,532 samples, 0.04%)<T as core::convert::TryInto<U>>::try_into (5,206,385 samples, 0.02%)core::convert::num::<impl core::convert::TryFrom<u128> for u64>::try_from (5,206,385 samples, 0.02%)__vdso_clock_gettime (4,664,666 samples, 0.02%)<tokio::time::timeout::Timeout<T> as core::future::future::Future>::poll::_{{closure}} (136,709,051 samples, 0.58%)<tokio::time::sleep::Sleep as core::future::future::Future>::poll (125,402,190 samples, 0.53%)tokio::time::sleep::Sleep::poll_elapsed (125,402,190 samples, 0.53%)tokio::runtime::time::entry::TimerEntry::poll_elapsed (121,309,858 samples, 0.51%)tokio::runtime::time::entry::TimerEntry::reset (85,254,486 samples, 0.36%)tokio::runtime::time::source::TimeSource::deadline_to_tick (15,609,443 samples, 0.07%)tokio::runtime::time::source::TimeSource::instant_to_tick (15,609,443 samples, 0.07%)tokio::time::instant::Instant::saturating_duration_since (10,403,058 samples, 0.04%)std::time::Instant::duration_since (10,403,058 samples, 0.04%)std::time::Instant::checked_duration_since (10,403,058 samples, 0.04%)std::sys::pal::unix::time::Instant::checked_sub_instant (10,403,058 samples, 0.04%)std::sys::pal::unix::time::Timespec::sub_timespec (5,738,392 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::pool::connection::binding::Binding::read::{{closure}}> (14,759,243 samples, 0.06%)<F as core::future::into_future::IntoFuture>::into_future (6,755,187 samples, 0.03%)core::task::poll::Poll<T>::map (4,875,014 samples, 0.02%)core::ptr::drop_in_place<tokio::time::sleep::Sleep::poll_elapsed::{{closure}}> (4,875,014 samples, 0.02%)core::ptr::drop_in_place<tokio::runtime::coop::RestoreOnPending> (4,875,014 samples, 0.02%)<tokio::runtime::coop::RestoreOnPending as core::ops::drop::Drop>::drop (4,875,014 samples, 0.02%)tokio::runtime::context::budget (4,875,014 samples, 0.02%)std::thread::local::LocalKey<T>::try_with (4,875,014 samples, 0.02%)tokio::runtime::context::budget::_{{closure}} (4,875,014 samples, 0.02%)<tokio::runtime::coop::RestoreOnPending as core::ops::drop::Drop>::drop::_{{closure}} (4,875,014 samples, 0.02%)core::cell::Cell<T>::set (4,875,014 samples, 0.02%)core::cell::Cell<T>::replace (4,875,014 samples, 0.02%)core::mem::replace (4,875,014 samples, 0.02%)core::ptr::write (4,875,014 samples, 0.02%)tokio::runtime::coop::poll_proceed (5,852,007 samples, 0.02%)tokio::runtime::context::budget (5,852,007 samples, 0.02%)std::thread::local::LocalKey<T>::try_with (5,852,007 samples, 0.02%)tokio::runtime::context::budget::_{{closure}} (5,852,007 samples, 0.02%)tokio::runtime::coop::poll_proceed::_{{closure}} (5,852,007 samples, 0.02%)tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut (3,220,462 samples, 0.01%)tokio::sync::task::atomic_waker::AtomicWaker::do_register::_{{closure}} (3,220,462 samples, 0.01%)tokio::runtime::time::entry::StateCell::poll (17,238,223 samples, 0.07%)tokio::sync::task::atomic_waker::AtomicWaker::register_by_ref (17,238,223 samples, 0.07%)tokio::sync::task::atomic_waker::AtomicWaker::do_register (17,238,223 samples, 0.07%)tokio::sync::task::atomic_waker::AtomicWaker::do_register::catch_unwind (3,756,384 samples, 0.02%)std::panic::catch_unwind (3,756,384 samples, 0.02%)std::panicking::try (3,756,384 samples, 0.02%)std::panicking::try::do_call (3,756,384 samples, 0.02%)<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once (3,756,384 samples, 0.02%)tokio::sync::task::atomic_waker::AtomicWaker::do_register::_{{closure}} (3,756,384 samples, 0.02%)core::mem::drop (3,756,384 samples, 0.02%)core::ptr::drop_in_place<core::option::Option<core::task::wake::Waker>> (3,756,384 samples, 0.02%)core::ptr::drop_in_place<core::task::wake::Waker> (3,756,384 samples, 0.02%)<core::task::wake::Waker as core::ops::drop::Drop>::drop (3,756,384 samples, 0.02%)tokio::runtime::task::waker::drop_waker (3,756,384 samples, 0.02%)tokio::runtime::task::harness::<impl tokio::runtime::task::raw::RawTask>::drop_reference (3,756,384 samples, 0.02%)tokio::runtime::task::state::State::ref_dec (3,756,384 samples, 0.02%)core::sync::atomic::AtomicUsize::fetch_sub (3,756,384 samples, 0.02%)core::sync::atomic::atomic_sub (3,756,384 samples, 0.02%)tokio::runtime::time::entry::TimerEntry::inner (5,562,832 samples, 0.02%)core::option::Option<T>::map (4,943,080 samples, 0.02%)tokio::runtime::time::entry::TimerHandle::cached_when (4,948,523 samples, 0.02%)tokio::runtime::time::entry::TimerShared::cached_when (4,948,523 samples, 0.02%)core::sync::atomic::AtomicU64::load (4,948,523 samples, 0.02%)core::sync::atomic::atomic_load (4,948,523 samples, 0.02%)tokio::runtime::time::wheel::level::slot_for (3,241,604 samples, 0.01%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::reregister (19,280,929 samples, 0.08%)tokio::runtime::time::wheel::Wheel::insert (14,337,849 samples, 0.06%)tokio::runtime::time::wheel::level::Level::add_entry (14,337,849 samples, 0.06%)tokio::util::linked_list::LinkedList<L,<L as tokio::util::linked_list::Link>::Target>::push_front (6,147,722 samples, 0.03%)core::option::Option<T>::is_none (6,147,722 samples, 0.03%)core::option::Option<T>::is_some (6,147,722 samples, 0.03%)<tokio::time::sleep::Sleep as core::future::future::Future>::poll (59,138,813 samples, 0.25%)tokio::time::sleep::Sleep::poll_elapsed (59,138,813 samples, 0.25%)tokio::runtime::time::entry::TimerEntry::poll_elapsed (48,411,792 samples, 0.20%)tokio::runtime::time::entry::TimerEntry::reset (25,610,737 samples, 0.11%)tokio::runtime::time::source::TimeSource::deadline_to_tick (4,353,609 samples, 0.02%)tokio::runtime::time::source::TimeSource::instant_to_tick (4,353,609 samples, 0.02%)tokio::time::instant::Instant::saturating_duration_since (4,353,609 samples, 0.02%)std::time::Instant::duration_since (4,353,609 samples, 0.02%)std::time::Instant::checked_duration_since (4,353,609 samples, 0.02%)std::sys::pal::unix::time::Instant::checked_sub_instant (4,353,609 samples, 0.02%)std::sys::pal::unix::time::Timespec::sub_timespec (4,353,609 samples, 0.02%)core::cmp::impls::<impl core::cmp::PartialOrd<&B> for &A>::ge (4,353,609 samples, 0.02%)core::cmp::PartialOrd::ge (4,353,609 samples, 0.02%)<std::sys::pal::unix::time::Timespec as core::cmp::PartialOrd>::partial_cmp (4,353,609 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::error::Error> (4,005,981 samples, 0.02%)<tracing_core::metadata::Level as core::cmp::PartialOrd<tracing_core::metadata::LevelFilter>>::le (5,380,200 samples, 0.02%)pgdog::backend::server::Server::stream (4,167,105 samples, 0.02%)core::option::Option<T>::as_mut (4,167,105 samples, 0.02%)<tokio::io::util::read_exact::ReadExact<A> as core::future::future::Future>::poll (3,129,474 samples, 0.01%)<&mut T as tokio::io::async_read::AsyncRead>::poll_read (3,129,474 samples, 0.01%)<arc_swap::strategy::hybrid::HybridStrategy<Cfg> as arc_swap::strategy::sealed::InnerStrategy<T>>::load::_{{closure}} (3,129,474 samples, 0.01%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (5,845,724 samples, 0.02%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_read::AsyncRead>::poll_read (5,845,724 samples, 0.02%)tokio::io::read_buf::ReadBuf::put_slice (2,405,943 samples, 0.01%)core::ptr::mut_ptr::<impl *mut T>::copy_from_nonoverlapping (2,405,943 samples, 0.01%)core::intrinsics::copy_nonoverlapping (2,405,943 samples, 0.01%)[libc.so.6] (2,405,943 samples, 0.01%)<&mut T as tokio::io::async_read::AsyncRead>::poll_read (14,595,229 samples, 0.06%)<pgdog::net::stream::Stream as tokio::io::async_read::AsyncRead>::poll_read (14,595,229 samples, 0.06%)pgdog::net::stream::_::<impl pgdog::net::stream::Stream>::project (5,634,340 samples, 0.02%)<tokio::io::util::read_int::ReadI32<R> as core::future::future::Future>::poll (33,766,595 samples, 0.14%)tokio::io::read_buf::ReadBuf::filled (19,171,366 samples, 0.08%)core::slice::index::<impl core::ops::index::Index<I> for [T]>::index (19,171,366 samples, 0.08%)<core::ops::range::RangeTo<usize> as core::slice::index::SliceIndex<[T]>>::index (19,171,366 samples, 0.08%)<core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::index (19,171,366 samples, 0.08%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_buf_read::AsyncBufRead>::consume (2,968,680 samples, 0.01%)asm_sysvec_apic_timer_interrupt (3,576,877 samples, 0.02%)sysvec_apic_timer_interrupt (3,576,877 samples, 0.02%)__sysvec_apic_timer_interrupt (3,576,877 samples, 0.02%)hrtimer_interrupt (3,576,877 samples, 0.02%)__hrtimer_run_queues (3,576,877 samples, 0.02%)tick_nohz_handler (3,576,877 samples, 0.02%)update_process_times (3,576,877 samples, 0.02%)sched_tick (3,576,877 samples, 0.02%)task_tick_fair (3,576,877 samples, 0.02%)update_curr (3,576,877 samples, 0.02%)fdget (44,236,317 samples, 0.19%)__rcu_read_unlock (8,204,819 samples, 0.03%)fput (3,604,517 samples, 0.02%)__local_bh_enable_ip (12,206,978 samples, 0.05%)lock_sock_nested (6,825,475 samples, 0.03%)release_sock (9,862,689 samples, 0.04%)_raw_spin_lock_bh (4,715,504 samples, 0.02%)tcp_recv_timestamp (6,929,214 samples, 0.03%)__sk_mem_reduce_allocated (17,077,574 samples, 0.07%)mem_cgroup_uncharge_skmem (13,367,217 samples, 0.06%)mod_memcg_state (13,367,217 samples, 0.06%)__mod_memcg_state (13,367,217 samples, 0.06%)__tcp_cleanup_rbuf (12,787,435 samples, 0.05%)__tcp_select_window (7,316,920 samples, 0.03%)asm_sysvec_apic_timer_interrupt (4,062,282 samples, 0.02%)sysvec_apic_timer_interrupt (4,062,282 samples, 0.02%)__sysvec_apic_timer_interrupt (4,062,282 samples, 0.02%)hrtimer_interrupt (4,062,282 samples, 0.02%)__hrtimer_run_queues (4,062,282 samples, 0.02%)tick_nohz_handler (4,062,282 samples, 0.02%)update_process_times (4,062,282 samples, 0.02%)sched_tick (4,062,282 samples, 0.02%)task_tick_fair (4,062,282 samples, 0.02%)skb_attempt_defer_free (11,692,141 samples, 0.05%)__local_bh_enable_ip (4,487,606 samples, 0.02%)_copy_to_iter (12,351,055 samples, 0.05%)skb_copy_datagram_iter (44,247,049 samples, 0.19%)__skb_datagram_iter (35,226,666 samples, 0.15%)simple_copy_to_iter (14,192,485 samples, 0.06%)__check_object_size (14,192,485 samples, 0.06%)__virt_addr_valid (5,924,302 samples, 0.03%)sock_rfree (3,676,455 samples, 0.02%)inet_recvmsg (171,849,270 samples, 0.73%)tcp_recvmsg (161,567,154 samples, 0.68%)tcp_recvmsg_locked (116,480,559 samples, 0.49%)__x64_sys_recvfrom (294,092,029 samples, 1.24%)__sys_recvfrom (275,441,858 samples, 1.16%)sock_recvmsg (206,578,499 samples, 0.87%)security_socket_recvmsg (11,336,755 samples, 0.05%)srso_alias_return_thunk (10,534,754 samples, 0.04%)srso_alias_safe_ret (10,534,754 samples, 0.04%)arch_exit_to_user_mode_prepare.isra.0 (24,042,524 samples, 0.10%)do_syscall_64 (359,687,072 samples, 1.52%)syscall_exit_to_user_mode (46,009,074 samples, 0.19%)syscall_exit_to_user_mode_prepare (5,711,792 samples, 0.02%)[libc.so.6] (374,613,636 samples, 1.58%)entry_SYSCALL_64_after_hwframe (369,671,154 samples, 1.56%)srso_alias_return_thunk (5,163,319 samples, 0.02%)srso_alias_safe_ret (5,163,319 samples, 0.02%)[libc.so.6] (398,563,905 samples, 1.68%)asm_sysvec_apic_timer_interrupt (4,141,435 samples, 0.02%)sysvec_apic_timer_interrupt (4,141,435 samples, 0.02%)__sysvec_apic_timer_interrupt (4,141,435 samples, 0.02%)hrtimer_interrupt (4,141,435 samples, 0.02%)hrtimer_update_next_event (4,141,435 samples, 0.02%)recv (414,474,549 samples, 1.75%)[libc.so.6] (406,036,447 samples, 1.71%)__vdso_clock_gettime (3,332,486 samples, 0.01%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read (419,789,875 samples, 1.77%)<..mio::io_source::IoSource<T>::do_io (419,789,875 samples, 1.77%)m..mio::sys::unix::selector::stateless_io_source::IoSourceState::do_io (419,789,875 samples, 1.77%)m..<&mio::net::tcp::stream::TcpStream as std::io::Read>::read::_{{closure}} (419,789,875 samples, 1.77%)<..<&std::net::tcp::TcpStream as std::io::Read>::read (419,789,875 samples, 1.77%)<..std::sys::net::connection::socket::TcpStream::read (419,789,875 samples, 1.77%)s..std::sys::net::connection::socket::unix::Socket::read (419,789,875 samples, 1.77%)s..std::sys::net::connection::socket::unix::Socket::recv_with_flags (419,789,875 samples, 1.77%)s..std::sys::pal::unix::cvt (5,315,326 samples, 0.02%)<isize as std::sys::pal::unix::IsMinusOne>::is_minus_one (5,315,326 samples, 0.02%)<core::result::Result<T,E> as core::ops::try_trait::Try>::branch (3,804,419 samples, 0.02%)tokio::runtime::io::registration::Registration::clear_readiness (3,749,516 samples, 0.02%)tokio::runtime::io::scheduled_io::ScheduledIo::clear_readiness (3,749,516 samples, 0.02%)tokio::runtime::io::scheduled_io::ScheduledIo::set_readiness (3,749,516 samples, 0.02%)core::sync::atomic::AtomicUsize::fetch_update (3,749,516 samples, 0.02%)core::sync::atomic::AtomicUsize::load (3,749,516 samples, 0.02%)core::sync::atomic::atomic_load (3,749,516 samples, 0.02%)<core::task::wake::Waker as core::clone::Clone>::clone (3,727,594 samples, 0.02%)tokio::runtime::task::waker::clone_waker (3,727,594 samples, 0.02%)tokio::runtime::task::state::State::ref_inc (3,727,594 samples, 0.02%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_buf_read::AsyncBufRead>::poll_fill_buf (465,105,775 samples, 1.96%)<..<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_read::AsyncRead>::poll_read (465,105,775 samples, 1.96%)<..<tokio::net::tcp::stream::TcpStream as tokio::io::async_read::AsyncRead>::poll_read (465,105,775 samples, 1.96%)<..tokio::net::tcp::stream::TcpStream::poll_read_priv (465,105,775 samples, 1.96%)t..tokio::io::poll_evented::PollEvented<E>::poll_read (465,105,775 samples, 1.96%)t..tokio::runtime::io::registration::Registration::poll_read_ready (8,639,257 samples, 0.04%)tokio::runtime::io::registration::Registration::poll_ready (8,639,257 samples, 0.04%)tokio::runtime::io::scheduled_io::ScheduledIo::poll_readiness (8,639,257 samples, 0.04%)core::ptr::drop_in_place<tokio::loom::std::parking_lot::MutexGuard<tokio::runtime::io::scheduled_io::Waiters>> (4,911,663 samples, 0.02%)core::ptr::drop_in_place<lock_api::mutex::MutexGuard<parking_lot::raw_mutex::RawMutex,tokio::runtime::io::scheduled_io::Waiters>> (4,911,663 samples, 0.02%)<lock_api::mutex::MutexGuard<R,T> as core::ops::drop::Drop>::drop (4,911,663 samples, 0.02%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::unlock (4,911,663 samples, 0.02%)core::sync::atomic::AtomicU8::compare_exchange (4,911,663 samples, 0.02%)core::sync::atomic::atomic_compare_exchange (4,911,663 samples, 0.02%)[libc.so.6] (19,153,716 samples, 0.08%)<tokio::io::util::read_int::ReadU8<R> as core::future::future::Future>::poll (504,649,178 samples, 2.13%)<..<&mut T as tokio::io::async_read::AsyncRead>::poll_read (498,248,289 samples, 2.10%)<..<pgdog::net::stream::Stream as tokio::io::async_read::AsyncRead>::poll_read (498,248,289 samples, 2.10%)<..<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (498,222,802 samples, 2.10%)<..<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_read::AsyncRead>::poll_read (498,222,802 samples, 2.10%)<..tokio::io::read_buf::ReadBuf::put_slice (30,148,347 samples, 0.13%)core::ptr::mut_ptr::<impl *mut T>::copy_from_nonoverlapping (25,250,224 samples, 0.11%)core::intrinsics::copy_nonoverlapping (25,250,224 samples, 0.11%)recv (6,096,508 samples, 0.03%)bytes::bytes_mut::BytesMut::freeze (10,528,822 samples, 0.04%)<T as core::convert::Into<U>>::into (5,716,500 samples, 0.02%)<bytes::bytes::Bytes as core::convert::From<alloc::vec::Vec<u8>>>::from (5,716,500 samples, 0.02%)alloc::vec::Vec<T>::with_capacity (30,878,171 samples, 0.13%)alloc::vec::Vec<T,A>::with_capacity_in (30,878,171 samples, 0.13%)alloc::raw_vec::RawVec<T,A>::with_capacity_in (30,878,171 samples, 0.13%)alloc::raw_vec::RawVecInner<A>::with_capacity_in (30,878,171 samples, 0.13%)alloc::raw_vec::RawVecInner<A>::try_allocate_in (30,878,171 samples, 0.13%)<alloc::alloc::Global as core::alloc::Allocator>::allocate (30,878,171 samples, 0.13%)alloc::alloc::Global::alloc_impl (30,878,171 samples, 0.13%)alloc::alloc::alloc (30,878,171 samples, 0.13%)__rust_alloc (30,878,171 samples, 0.13%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::alloc (30,878,171 samples, 0.13%)_rjem_malloc (30,878,171 samples, 0.13%)imalloc_fastpath (30,878,171 samples, 0.13%)cache_bin_alloc_easy (5,039,250 samples, 0.02%)cache_bin_alloc_impl (5,039,250 samples, 0.02%)bytes::bytes_mut::BytesMut::with_capacity (35,324,405 samples, 0.15%)bytes::bytes_mut::BytesMut::from_vec (4,446,234 samples, 0.02%)pgdog::backend::server::Server::read::_{{closure}} (722,358,888 samples, 3.05%)pgd..pgdog::net::stream::Stream::read::_{{closure}} (625,665,464 samples, 2.64%)pg..core::slice::index::<impl core::ops::index::IndexMut<I> for [T]>::index_mut (3,111,649 samples, 0.01%)<core::ops::range::RangeFrom<usize> as core::slice::index::SliceIndex<[T]>>::index_mut (3,111,649 samples, 0.01%)tokio::time::sleep::Sleep::new_timeout (5,008,874 samples, 0.02%)tokio::time::instant::Instant::far_future (24,864,396 samples, 0.10%)tokio::time::instant::Instant::now (24,864,396 samples, 0.10%)tokio::time::instant::variant::now (24,864,396 samples, 0.10%)std::time::Instant::now (24,864,396 samples, 0.10%)std::sys::pal::unix::time::Instant::now (24,864,396 samples, 0.10%)std::sys::pal::unix::time::Timespec::now (24,864,396 samples, 0.10%)clock_gettime (24,864,396 samples, 0.10%)__vdso_clock_gettime (19,829,131 samples, 0.08%)[unknown] (3,259,737 samples, 0.01%)pgdog::backend::pool::connection::Connection::disconnect (3,259,737 samples, 0.01%)pgdog::backend::pool::connection::binding::Binding::disconnect (3,259,737 samples, 0.01%)pgdog::backend::pool::connection::Connection::read::_{{closure}} (916,872,773 samples, 3.87%)pgdo..pgdog::backend::pool::connection::binding::Binding::read::_{{closure}} (850,008,586 samples, 3.59%)pgdo..tokio::time::sleep::sleep (36,538,633 samples, 0.15%)tokio::time::instant::Instant::now (11,674,237 samples, 0.05%)tokio::time::instant::variant::now (11,674,237 samples, 0.05%)std::time::Instant::now (11,674,237 samples, 0.05%)std::sys::pal::unix::time::Instant::now (11,674,237 samples, 0.05%)std::sys::pal::unix::time::Timespec::now (8,414,500 samples, 0.04%)clock_gettime (8,414,500 samples, 0.04%)__vdso_clock_gettime (8,414,500 samples, 0.04%)core::result::Result<T,E>::unwrap_or (3,364,953 samples, 0.01%)<tokio::time::timeout::Timeout<T> as core::future::future::Future>::poll (1,076,030,859 samples, 4.54%)<toki..tokio::runtime::coop::has_budget_remaining (18,220,151 samples, 0.08%)tokio::runtime::context::budget (14,855,198 samples, 0.06%)std::thread::local::LocalKey<T>::try_with (14,855,198 samples, 0.06%)core::ops::function::FnOnce::call_once (14,855,198 samples, 0.06%)tokio::runtime::context::CONTEXT::_{{constant}}::_{{closure}} (14,855,198 samples, 0.06%)std::sys::thread_local::native::eager::Storage<T>::get (14,855,198 samples, 0.06%)core::cell::Cell<T>::get (8,642,397 samples, 0.04%)__vdso_clock_gettime (4,207,733 samples, 0.02%)core::iter::range::<impl core::iter::traits::iterator::Iterator for core::ops::range::Range<A>>::next (7,486,196 samples, 0.03%)<core::ops::range::Range<T> as core::iter::range::RangeIteratorImpl>::spec_next (7,486,196 samples, 0.03%)core::cmp::impls::<impl core::cmp::PartialOrd for u32>::lt (7,486,196 samples, 0.03%)<core::result::Result<T,E> as core::ops::try_trait::Try>::branch (3,395,129 samples, 0.01%)<core::result::Result<T,E> as core::ops::try_trait::Try>::branch (16,185,668 samples, 0.07%)<bytes::bytes::Bytes as core::clone::Clone>::clone (4,450,568 samples, 0.02%)bytes::bytes::shared_clone (4,450,568 samples, 0.02%)bytes::bytes::shallow_clone_arc (4,450,568 samples, 0.02%)core::sync::atomic::AtomicUsize::fetch_add (4,450,568 samples, 0.02%)core::sync::atomic::atomic_add (4,450,568 samples, 0.02%)bytes::buf::buf_impl::Buf::get_i16 (5,947,376 samples, 0.03%)<bytes::bytes::Bytes as bytes::buf::buf_impl::Buf>::advance (3,810,757 samples, 0.02%)bytes::bytes::Bytes::inc_start (3,810,757 samples, 0.02%)<pgdog::net::messages::bind::Bind as pgdog::net::messages::FromBytes>::from_bytes (14,497,663 samples, 0.06%)pgdog::net::c_string_buf (4,099,719 samples, 0.02%)<pgdog::net::messages::describe::Describe as pgdog::net::messages::FromBytes>::from_bytes (9,360,293 samples, 0.04%)bytes::bytes::shallow_clone_arc (5,397,476 samples, 0.02%)core::sync::atomic::AtomicUsize::fetch_add (5,397,476 samples, 0.02%)core::sync::atomic::atomic_add (5,397,476 samples, 0.02%)<bytes::bytes::Bytes as core::clone::Clone>::clone (12,222,622 samples, 0.05%)bytes::bytes::shared_clone (12,222,622 samples, 0.05%)core::sync::atomic::AtomicPtr<T>::load (6,825,146 samples, 0.03%)core::sync::atomic::atomic_load (6,825,146 samples, 0.03%)<pgdog::net::stream::Stream as tokio::io::async_read::AsyncRead>::poll_read (6,915,954 samples, 0.03%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (6,915,954 samples, 0.03%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_read::AsyncRead>::poll_read (6,915,954 samples, 0.03%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_buf_read::AsyncBufRead>::poll_fill_buf (6,915,954 samples, 0.03%)tokio::io::read_buf::ReadBuf::filled (6,915,954 samples, 0.03%)_rjem_je_malloc_default (7,069,335 samples, 0.03%)alloc::sync::Arc<T>::new (33,249,327 samples, 0.14%)alloc::boxed::Box<T>::new (33,249,327 samples, 0.14%)alloc::alloc::exchange_malloc (24,410,754 samples, 0.10%)<alloc::alloc::Global as core::alloc::Allocator>::allocate (24,410,754 samples, 0.10%)alloc::alloc::Global::alloc_impl (24,410,754 samples, 0.10%)alloc::alloc::alloc (24,410,754 samples, 0.10%)__rust_alloc (24,410,754 samples, 0.10%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::alloc (24,410,754 samples, 0.10%)_rjem_malloc (17,341,419 samples, 0.07%)imalloc_fastpath (17,341,419 samples, 0.07%)cache_bin_alloc_easy (13,735,573 samples, 0.06%)cache_bin_alloc_impl (13,735,573 samples, 0.06%)alloc::string::String::push (107,637,031 samples, 0.45%)alloc::vec::Vec<T,A>::push (54,000,950 samples, 0.23%)bytes::buf::buf_impl::Buf::get_u8 (13,300,944 samples, 0.06%)<bytes::bytes::Bytes as bytes::buf::buf_impl::Buf>::advance (8,625,107 samples, 0.04%)bytes::bytes::Bytes::inc_start (8,625,107 samples, 0.04%)<pgdog::net::messages::parse::Parse as pgdog::net::messages::FromBytes>::from_bytes (216,160,971 samples, 0.91%)pgdog::net::c_string_buf (163,773,068 samples, 0.69%)pgdog::net::c_string_buf_len (30,404,846 samples, 0.13%)bytes::buf::buf_impl::Buf::has_remaining (15,400,753 samples, 0.07%)bytes::bytes::shared_drop (11,517,745 samples, 0.05%)<core::sync::atomic::AtomicPtr<T> as bytes::loom::sync::atomic::AtomicMut<T>>::with_mut (11,517,745 samples, 0.05%)bytes::bytes::shared_drop::_{{closure}} (11,517,745 samples, 0.05%)<pgdog::backend::protocol::protocol_message::ProtocolMessage as pgdog::net::messages::FromBytes>::from_bytes (289,348,275 samples, 1.22%)pgdog::net::stream::Stream::read::_{{closure}} (4,214,430 samples, 0.02%)<tokio::io::util::read_exact::ReadExact<A> as core::future::future::Future>::poll (4,214,430 samples, 0.02%)<&mut T as tokio::io::async_read::AsyncRead>::poll_read (4,214,430 samples, 0.02%)<pgdog::net::stream::Stream as tokio::io::async_read::AsyncRead>::poll_read (4,214,430 samples, 0.02%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (4,214,430 samples, 0.02%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_read::AsyncRead>::poll_read (4,214,430 samples, 0.02%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_buf_read::AsyncBufRead>::poll_fill_buf (4,214,430 samples, 0.02%)<pgdog::net::messages::Message as pgdog::net::messages::ToBytes>::to_bytes (47,193,545 samples, 0.20%)<bytes::bytes::Bytes as core::clone::Clone>::clone (47,193,545 samples, 0.20%)bytes::bytes::promotable_even_clone (47,193,545 samples, 0.20%)bytes::bytes::shallow_clone_vec (43,879,463 samples, 0.19%)alloc::boxed::Box<T>::new (19,049,749 samples, 0.08%)alloc::alloc::exchange_malloc (14,844,186 samples, 0.06%)<alloc::alloc::Global as core::alloc::Allocator>::allocate (14,844,186 samples, 0.06%)alloc::alloc::Global::alloc_impl (14,844,186 samples, 0.06%)alloc::alloc::alloc (14,844,186 samples, 0.06%)__rust_alloc (14,844,186 samples, 0.06%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::alloc (14,844,186 samples, 0.06%)_rjem_malloc (14,844,186 samples, 0.06%)imalloc_fastpath (14,844,186 samples, 0.06%)cache_bin_alloc_easy (7,873,608 samples, 0.03%)cache_bin_alloc_impl (7,873,608 samples, 0.03%)alloc::vec::Vec<T,A>::push (30,023,066 samples, 0.13%)core::ptr::write (30,023,066 samples, 0.13%)[libc.so.6] (24,544,244 samples, 0.10%)core::ptr::drop_in_place<pgdog::net::messages::Message> (16,637,390 samples, 0.07%)core::ptr::drop_in_place<bytes::bytes::Bytes> (16,637,390 samples, 0.07%)<bytes::bytes::Bytes as core::ops::drop::Drop>::drop (16,637,390 samples, 0.07%)bytes::bytes::promotable_even_drop (16,637,390 samples, 0.07%)<core::sync::atomic::AtomicPtr<T> as bytes::loom::sync::atomic::AtomicMut<T>>::with_mut (16,637,390 samples, 0.07%)<alloc::sync::Arc<T,A> as core::clone::Clone>::clone (10,021,573 samples, 0.04%)arc_swap::ArcSwapAny<T,S>::load (21,838,058 samples, 0.09%)<arc_swap::strategy::hybrid::HybridStrategy<Cfg> as arc_swap::strategy::sealed::InnerStrategy<T>>::load (21,838,058 samples, 0.09%)arc_swap::debt::list::LocalNode::with (21,838,058 samples, 0.09%)std::thread::local::LocalKey<T>::try_with (21,838,058 samples, 0.09%)arc_swap::debt::list::LocalNode::with::_{{closure}} (21,838,058 samples, 0.09%)<arc_swap::strategy::hybrid::HybridStrategy<Cfg> as arc_swap::strategy::sealed::InnerStrategy<T>>::load::_{{closure}} (16,593,586 samples, 0.07%)arc_swap::strategy::hybrid::HybridProtection<T>::attempt (12,744,676 samples, 0.05%)arc_swap::debt::list::LocalNode::new_fast (12,744,676 samples, 0.05%)arc_swap::debt::fast::Slots::get_debt (12,744,676 samples, 0.05%)pgdog::config::config (44,124,939 samples, 0.19%)core::ptr::drop_in_place<arc_swap::Guard<alloc::sync::Arc<pgdog::config::ConfigAndUsers>>> (12,265,308 samples, 0.05%)core::ptr::drop_in_place<arc_swap::strategy::hybrid::HybridProtection<alloc::sync::Arc<pgdog::config::ConfigAndUsers>>> (12,265,308 samples, 0.05%)<arc_swap::strategy::hybrid::HybridProtection<T> as core::ops::drop::Drop>::drop (12,265,308 samples, 0.05%)pgdog::frontend::buffer::Buffer::full (5,348,900 samples, 0.02%)<pgdog::backend::protocol::protocol_message::ProtocolMessage as pgdog::net::messages::Protocol>::code (5,348,900 samples, 0.02%)__vdso_clock_gettime (3,524,126 samples, 0.01%)_rjem_je_malloc_default (8,444,205 samples, 0.04%)imalloc (8,444,205 samples, 0.04%)imalloc_body (8,444,205 samples, 0.04%)thread_alloc_event (8,444,205 samples, 0.04%)te_event_advance (8,444,205 samples, 0.04%)_rjem_je_te_event_trigger (4,920,079 samples, 0.02%)_rjem_je_tcache_gc_event_handler (4,920,079 samples, 0.02%)tcache_event (4,920,079 samples, 0.02%)_rjem_je_tcache_bin_flush_stashed (4,920,079 samples, 0.02%)cache_bin_ncached_get_local (4,920,079 samples, 0.02%)cache_bin_ncached_get_internal (4,920,079 samples, 0.02%)pgdog::frontend::buffer::Buffer::new (26,148,855 samples, 0.11%)alloc::vec::Vec<T>::with_capacity (26,148,855 samples, 0.11%)alloc::vec::Vec<T,A>::with_capacity_in (26,148,855 samples, 0.11%)alloc::raw_vec::RawVec<T,A>::with_capacity_in (26,148,855 samples, 0.11%)alloc::raw_vec::RawVecInner<A>::with_capacity_in (26,148,855 samples, 0.11%)alloc::raw_vec::RawVecInner<A>::try_allocate_in (26,148,855 samples, 0.11%)<alloc::alloc::Global as core::alloc::Allocator>::allocate (26,148,855 samples, 0.11%)alloc::alloc::Global::alloc_impl (26,148,855 samples, 0.11%)alloc::alloc::alloc (26,148,855 samples, 0.11%)__rust_alloc (26,148,855 samples, 0.11%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::alloc (26,148,855 samples, 0.11%)_rjem_malloc (17,704,650 samples, 0.07%)imalloc_fastpath (17,704,650 samples, 0.07%)cache_bin_alloc_easy (3,521,351 samples, 0.01%)cache_bin_alloc_impl (3,521,351 samples, 0.01%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (6,524,714 samples, 0.03%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_read::AsyncRead>::poll_read (6,524,714 samples, 0.03%)tokio::io::read_buf::ReadBuf::put_slice (6,524,714 samples, 0.03%)<tokio::io::util::read_exact::ReadExact<A> as core::future::future::Future>::poll (24,990,092 samples, 0.11%)<&mut T as tokio::io::async_read::AsyncRead>::poll_read (24,990,092 samples, 0.11%)<pgdog::net::stream::Stream as tokio::io::async_read::AsyncRead>::poll_read (24,990,092 samples, 0.11%)pgdog::net::stream::_::<impl pgdog::net::stream::Stream>::project (9,182,953 samples, 0.04%)<pgdog::net::stream::Stream as tokio::io::async_read::AsyncRead>::poll_read (13,586,004 samples, 0.06%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (13,586,004 samples, 0.06%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_read::AsyncRead>::poll_read (13,586,004 samples, 0.06%)tokio::io::read_buf::ReadBuf::put_slice (13,586,004 samples, 0.06%)core::ptr::mut_ptr::<impl *mut T>::copy_from_nonoverlapping (4,778,135 samples, 0.02%)core::intrinsics::copy_nonoverlapping (4,778,135 samples, 0.02%)[libc.so.6] (4,778,135 samples, 0.02%)<&mut T as tokio::io::async_read::AsyncRead>::poll_read (17,538,059 samples, 0.07%)[libc.so.6] (3,952,055 samples, 0.02%)<tokio::io::util::read_int::ReadI32<R> as core::future::future::Future>::poll (29,098,559 samples, 0.12%)tokio::io::read_buf::ReadBuf::filled (11,560,500 samples, 0.05%)core::slice::index::<impl core::ops::index::Index<I> for [T]>::index (11,560,500 samples, 0.05%)<core::ops::range::RangeTo<usize> as core::slice::index::SliceIndex<[T]>>::index (11,560,500 samples, 0.05%)<core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::index (11,560,500 samples, 0.05%)fdget (32,399,899 samples, 0.14%)__rcu_read_unlock (5,832,815 samples, 0.02%)release_sock (7,253,137 samples, 0.03%)tcp_release_cb (2,598,461 samples, 0.01%)tcp_recv_timestamp (3,419,725 samples, 0.01%)__sk_mem_reduce_allocated (4,996,039 samples, 0.02%)mem_cgroup_uncharge_skmem (4,996,039 samples, 0.02%)mod_memcg_state (4,996,039 samples, 0.02%)__mod_memcg_state (4,996,039 samples, 0.02%)__tcp_cleanup_rbuf (7,582,380 samples, 0.03%)skb_attempt_defer_free (3,985,375 samples, 0.02%)_copy_to_iter (20,215,075 samples, 0.09%)inet_recvmsg (166,402,561 samples, 0.70%)tcp_recvmsg (156,830,844 samples, 0.66%)tcp_recvmsg_locked (140,952,490 samples, 0.60%)skb_copy_datagram_iter (78,072,105 samples, 0.33%)__skb_datagram_iter (78,072,105 samples, 0.33%)simple_copy_to_iter (24,544,097 samples, 0.10%)__check_object_size (24,544,097 samples, 0.10%)__virt_addr_valid (18,576,409 samples, 0.08%)__x64_sys_recvfrom (264,094,511 samples, 1.11%)__sys_recvfrom (259,045,435 samples, 1.09%)sock_recvmsg (193,774,727 samples, 0.82%)security_socket_recvmsg (12,516,709 samples, 0.05%)do_syscall_64 (322,758,984 samples, 1.36%)syscall_exit_to_user_mode (34,869,394 samples, 0.15%)arch_exit_to_user_mode_prepare.isra.0 (12,567,011 samples, 0.05%)recv (426,084,100 samples, 1.80%)r..[libc.so.6] (416,257,891 samples, 1.76%)[libc.so.6] (404,649,300 samples, 1.71%)[libc.so.6] (361,134,817 samples, 1.52%)entry_SYSCALL_64_after_hwframe (355,635,057 samples, 1.50%)srso_alias_return_thunk (19,420,687 samples, 0.08%)srso_alias_safe_ret (19,420,687 samples, 0.08%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read (431,607,823 samples, 1.82%)<..mio::io_source::IoSource<T>::do_io (431,607,823 samples, 1.82%)m..mio::sys::unix::selector::stateless_io_source::IoSourceState::do_io (431,607,823 samples, 1.82%)m..<&mio::net::tcp::stream::TcpStream as std::io::Read>::read::_{{closure}} (431,607,823 samples, 1.82%)<..<&std::net::tcp::TcpStream as std::io::Read>::read (431,607,823 samples, 1.82%)<..std::sys::net::connection::socket::TcpStream::read (431,607,823 samples, 1.82%)s..std::sys::net::connection::socket::unix::Socket::read (431,607,823 samples, 1.82%)s..std::sys::net::connection::socket::unix::Socket::recv_with_flags (431,607,823 samples, 1.82%)s..std::sys::pal::unix::cvt (5,523,723 samples, 0.02%)core::ptr::drop_in_place<tokio::runtime::coop::RestoreOnPending> (10,028,871 samples, 0.04%)<tokio::runtime::coop::RestoreOnPending as core::ops::drop::Drop>::drop (10,028,871 samples, 0.04%)tokio::loom::std::parking_lot::Mutex<T>::lock (4,194,814 samples, 0.02%)lock_api::mutex::Mutex<R,T>::lock (4,194,814 samples, 0.02%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::lock (4,194,814 samples, 0.02%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_buf_read::AsyncBufRead>::poll_fill_buf (477,982,771 samples, 2.02%)<..<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_read::AsyncRead>::poll_read (463,746,445 samples, 1.96%)<..<tokio::net::tcp::stream::TcpStream as tokio::io::async_read::AsyncRead>::poll_read (463,746,445 samples, 1.96%)<..tokio::net::tcp::stream::TcpStream::poll_read_priv (461,235,015 samples, 1.95%)t..tokio::io::poll_evented::PollEvented<E>::poll_read (461,235,015 samples, 1.95%)t..tokio::runtime::io::registration::Registration::poll_read_ready (18,024,284 samples, 0.08%)tokio::runtime::io::registration::Registration::poll_ready (18,024,284 samples, 0.08%)tokio::runtime::io::scheduled_io::ScheduledIo::poll_readiness (7,995,413 samples, 0.03%)tokio::runtime::io::driver::Direction::mask (3,190,202 samples, 0.01%)core::cmp::min (5,640,286 samples, 0.02%)core::cmp::Ord::min (5,640,286 samples, 0.02%)tokio::io::read_buf::ReadBuf::put_slice (22,363,983 samples, 0.09%)core::ptr::mut_ptr::<impl *mut T>::copy_from_nonoverlapping (13,144,517 samples, 0.06%)core::intrinsics::copy_nonoverlapping (13,144,517 samples, 0.06%)[libc.so.6] (13,144,517 samples, 0.06%)<&mut T as tokio::io::async_read::AsyncRead>::poll_read (518,530,104 samples, 2.19%)<..<pgdog::net::stream::Stream as tokio::io::async_read::AsyncRead>::poll_read (518,530,104 samples, 2.19%)<..<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (513,148,806 samples, 2.17%)<..<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_read::AsyncRead>::poll_read (513,148,806 samples, 2.17%)<..tokio::io::read_buf::ReadBuf::remaining (2,779,119 samples, 0.01%)<tokio::io::util::read_int::ReadU8<R> as core::future::future::Future>::poll (541,025,920 samples, 2.28%)<..tokio::io::read_buf::ReadBuf::filled (12,895,830 samples, 0.05%)core::slice::index::<impl core::ops::index::Index<I> for [T]>::index (12,895,830 samples, 0.05%)<core::ops::range::RangeTo<usize> as core::slice::index::SliceIndex<[T]>>::index (12,895,830 samples, 0.05%)<core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::index (12,895,830 samples, 0.05%)asm_sysvec_apic_timer_interrupt (5,780,506 samples, 0.02%)sysvec_apic_timer_interrupt (5,780,506 samples, 0.02%)__sysvec_apic_timer_interrupt (5,780,506 samples, 0.02%)hrtimer_interrupt (5,780,506 samples, 0.02%)__hrtimer_run_queues (5,780,506 samples, 0.02%)tick_nohz_handler (5,780,506 samples, 0.02%)update_process_times (5,780,506 samples, 0.02%)sched_tick (5,780,506 samples, 0.02%)task_tick_fair (5,780,506 samples, 0.02%)bytes::buf::buf_mut::BufMut::put_u8 (9,215,345 samples, 0.04%)<bytes::bytes_mut::BytesMut as bytes::buf::buf_mut::BufMut>::put_slice (9,215,345 samples, 0.04%)bytes::bytes_mut::BytesMut::extend_from_slice (9,215,345 samples, 0.04%)core::intrinsics::copy_nonoverlapping (9,215,345 samples, 0.04%)bytes::bytes_mut::BytesMut::resize (37,409,785 samples, 0.16%)core::intrinsics::write_bytes (37,409,785 samples, 0.16%)[libc.so.6] (37,409,785 samples, 0.16%)pgdog::net::stream::Stream::read::_{{closure}} (708,112,132 samples, 2.99%)pgd..bytes::bytes_mut::BytesMut::with_capacity (16,476,604 samples, 0.07%)alloc::vec::Vec<T>::with_capacity (16,476,604 samples, 0.07%)alloc::vec::Vec<T,A>::with_capacity_in (16,476,604 samples, 0.07%)alloc::raw_vec::RawVec<T,A>::with_capacity_in (16,476,604 samples, 0.07%)alloc::raw_vec::RawVecInner<A>::with_capacity_in (16,476,604 samples, 0.07%)alloc::raw_vec::RawVecInner<A>::try_allocate_in (16,476,604 samples, 0.07%)<alloc::alloc::Global as core::alloc::Allocator>::allocate (16,476,604 samples, 0.07%)alloc::alloc::Global::alloc_impl (16,476,604 samples, 0.07%)alloc::alloc::alloc (16,476,604 samples, 0.07%)__rust_alloc (16,476,604 samples, 0.07%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::alloc (16,476,604 samples, 0.07%)_rjem_malloc (16,476,604 samples, 0.07%)imalloc_fastpath (16,476,604 samples, 0.07%)cache_bin_alloc_easy (5,422,808 samples, 0.02%)cache_bin_alloc_impl (5,422,808 samples, 0.02%)clock_gettime (10,889,976 samples, 0.05%)__vdso_clock_gettime (10,889,976 samples, 0.05%)pgdog::frontend::client::Client::buffer::_{{closure}} (1,238,280,203 samples, 5.23%)pgdog:..std::time::Instant::now (15,357,662 samples, 0.06%)std::sys::pal::unix::time::Instant::now (15,357,662 samples, 0.06%)std::sys::pal::unix::time::Timespec::now (15,357,662 samples, 0.06%)core::result::Result<T,E>::unwrap (4,467,686 samples, 0.02%)core::ops::function::FnOnce::call_once (3,920,395 samples, 0.02%)tokio::runtime::context::CONTEXT::_{{constant}}::_{{closure}} (3,920,395 samples, 0.02%)std::sys::thread_local::native::eager::Storage<T>::get (3,920,395 samples, 0.02%)core::cell::Cell<T>::set (20,004,109 samples, 0.08%)core::cell::Cell<T>::replace (20,004,109 samples, 0.08%)core::mem::replace (20,004,109 samples, 0.08%)core::ptr::write (20,004,109 samples, 0.08%)core::option::Option<T>::unwrap_or_else (4,360,977 samples, 0.02%)<core::future::poll_fn::PollFn<F> as core::future::future::Future>::poll (2,439,445,401 samples, 10.30%)<core::future::..pgdog::frontend::client::Client::run::_{{closure}}::_{{closure}} (2,439,445,401 samples, 10.30%)pgdog::frontend..tokio::macros::support::thread_rng_n (34,717,143 samples, 0.15%)tokio::runtime::context::thread_rng_n (34,717,143 samples, 0.15%)std::thread::local::LocalKey<T>::with (34,717,143 samples, 0.15%)std::thread::local::LocalKey<T>::try_with (34,717,143 samples, 0.15%)tokio::runtime::context::thread_rng_n::_{{closure}} (30,796,748 samples, 0.13%)tokio::util::rand::FastRand::fastrand_n (6,431,662 samples, 0.03%)tokio::util::rand::FastRand::fastrand (6,431,662 samples, 0.03%)core::num::<impl u32>::wrapping_add (4,199,746 samples, 0.02%)<tokio::runtime::time::entry::TimerEntry as core::ops::drop::Drop>::drop (4,532,631 samples, 0.02%)tokio::runtime::time::entry::TimerEntry::cancel (4,532,631 samples, 0.02%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::clear_entry (4,532,631 samples, 0.02%)tokio::loom::std::parking_lot::RwLock<T>::read (4,532,631 samples, 0.02%)lock_api::rwlock::RwLock<R,T>::read (4,532,631 samples, 0.02%)<parking_lot::raw_rwlock::RawRwLock as lock_api::rwlock::RawRwLock>::lock_shared (4,532,631 samples, 0.02%)parking_lot::raw_rwlock::RawRwLock::try_lock_shared_fast (4,532,631 samples, 0.02%)tokio::sync::notify::AtomicNotification::load (13,003,376 samples, 0.05%)<tokio::sync::notify::Notified as core::ops::drop::Drop>::drop (16,117,600 samples, 0.07%)tokio::util::linked_list::LinkedList<L,<L as tokio::util::linked_list::Link>::Target>::remove (3,114,224 samples, 0.01%)tokio::util::linked_list::Pointers<T>::set_prev (3,114,224 samples, 0.01%)core::ptr::mut_ptr::<impl *mut T>::write (3,114,224 samples, 0.01%)core::ptr::write (3,114,224 samples, 0.01%)[libc.so.6] (3,790,299 samples, 0.02%)core::ptr::drop_in_place<tokio::sync::notify::Notified> (23,126,317 samples, 0.10%)core::ptr::drop_in_place<tokio::sync::notify::Waiter> (7,008,717 samples, 0.03%)core::ptr::drop_in_place<tokio::loom::std::unsafe_cell::UnsafeCell<core::option::Option<core::task::wake::Waker>>> (7,008,717 samples, 0.03%)core::ptr::drop_in_place<core::cell::UnsafeCell<core::option::Option<core::task::wake::Waker>>> (7,008,717 samples, 0.03%)core::ptr::drop_in_place<core::option::Option<core::task::wake::Waker>> (7,008,717 samples, 0.03%)core::ptr::drop_in_place<core::task::wake::Waker> (7,008,717 samples, 0.03%)<core::task::wake::Waker as core::ops::drop::Drop>::drop (7,008,717 samples, 0.03%)tokio::runtime::task::waker::drop_waker (3,218,418 samples, 0.01%)tokio::runtime::task::harness::<impl tokio::runtime::task::raw::RawTask>::drop_reference (3,218,418 samples, 0.01%)tokio::runtime::task::state::State::ref_dec (3,218,418 samples, 0.01%)bytes::bytes::promotable_even_drop (4,439,023 samples, 0.02%)<core::sync::atomic::AtomicPtr<T> as bytes::loom::sync::atomic::AtomicMut<T>>::with_mut (4,439,023 samples, 0.02%)bytes::bytes::promotable_even_drop::_{{closure}} (4,439,023 samples, 0.02%)bytes::bytes::release_shared (4,439,023 samples, 0.02%)core::sync::atomic::AtomicUsize::fetch_sub (4,439,023 samples, 0.02%)core::sync::atomic::atomic_sub (4,439,023 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::pool::connection::Connection::read::{{closure}}> (3,501,578 samples, 0.01%)core::ptr::drop_in_place<tokio::time::sleep::Sleep> (3,501,578 samples, 0.01%)core::ptr::drop_in_place<tokio::runtime::time::entry::TimerEntry> (3,501,578 samples, 0.01%)<tokio::runtime::time::entry::TimerEntry as core::ops::drop::Drop>::drop (3,501,578 samples, 0.01%)tokio::runtime::time::entry::TimerEntry::cancel (3,501,578 samples, 0.01%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::clear_entry (3,501,578 samples, 0.01%)bytes::bytes::promotable_even_clone (3,501,578 samples, 0.01%)core::sync::atomic::AtomicPtr<T>::load (3,501,578 samples, 0.01%)core::sync::atomic::atomic_load (3,501,578 samples, 0.01%)core::ptr::drop_in_place<core::option::Option<core::task::wake::Waker>> (10,569,825 samples, 0.04%)pgdog::net::c_string_buf (2,754,551 samples, 0.01%)tokio::runtime::time::ShardedWheel::lock_sharded_wheel (8,160,080 samples, 0.03%)tokio::loom::std::parking_lot::Mutex<T>::lock (8,160,080 samples, 0.03%)lock_api::mutex::Mutex<R,T>::lock (8,160,080 samples, 0.03%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::lock (8,160,080 samples, 0.03%)tokio::runtime::time::wheel::Wheel::level_for (3,332,198 samples, 0.01%)tokio::runtime::time::wheel::level_for (3,332,198 samples, 0.01%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::clear_entry (37,107,279 samples, 0.16%)tokio::runtime::time::wheel::Wheel::remove (15,622,823 samples, 0.07%)tokio::runtime::time::wheel::level::Level::remove_entry (12,290,625 samples, 0.05%)tokio::util::linked_list::LinkedList<L,<L as tokio::util::linked_list::Link>::Target>::remove (12,290,625 samples, 0.05%)core::cmp::PartialEq::ne (12,290,625 samples, 0.05%)<core::option::Option<T> as core::cmp::PartialEq>::eq (12,290,625 samples, 0.05%)<tokio::runtime::time::entry::TimerEntry as core::ops::drop::Drop>::drop (53,368,467 samples, 0.23%)tokio::runtime::time::entry::TimerEntry::cancel (51,076,480 samples, 0.22%)tokio::runtime::time::entry::TimerEntry::inner (13,969,201 samples, 0.06%)core::ptr::drop_in_place<(tokio::sync::notify::Notified,tokio::time::timeout::Timeout<pgdog::backend::pool::connection::Connection::read::{{closure}}>,pgdog::frontend::client::Client::buffer::{{closure}})> (99,095,181 samples, 0.42%)core::ptr::drop_in_place<tokio::time::timeout::Timeout<pgdog::backend::pool::connection::Connection::read::{{closure}}>> (75,968,864 samples, 0.32%)core::ptr::drop_in_place<tokio::time::sleep::Sleep> (64,252,458 samples, 0.27%)core::ptr::drop_in_place<tokio::runtime::time::entry::TimerEntry> (57,181,045 samples, 0.24%)core::ptr::drop_in_place<tokio::runtime::scheduler::Handle> (3,812,578 samples, 0.02%)core::ptr::drop_in_place<alloc::sync::Arc<tokio::runtime::scheduler::multi_thread::handle::Handle>> (3,812,578 samples, 0.02%)<alloc::sync::Arc<T,A> as core::ops::drop::Drop>::drop (3,812,578 samples, 0.02%)asm_sysvec_apic_timer_interrupt (3,822,405 samples, 0.02%)sysvec_apic_timer_interrupt (3,822,405 samples, 0.02%)__sysvec_apic_timer_interrupt (3,822,405 samples, 0.02%)hrtimer_interrupt (3,822,405 samples, 0.02%)__hrtimer_run_queues (3,822,405 samples, 0.02%)tick_nohz_handler (3,822,405 samples, 0.02%)update_process_times (3,822,405 samples, 0.02%)sched_tick (3,822,405 samples, 0.02%)psi_account_irqtime (3,822,405 samples, 0.02%)sched_clock_cpu (3,822,405 samples, 0.02%)sched_clock (3,822,405 samples, 0.02%)native_sched_clock (3,822,405 samples, 0.02%)core::ptr::drop_in_place<alloc::sync::Arc<pgdog::config::ConfigAndUsers>> (8,417,358 samples, 0.04%)<alloc::sync::Arc<T,A> as core::ops::drop::Drop>::drop (8,417,358 samples, 0.04%)[libc.so.6] (5,847,869 samples, 0.02%)_rjem_sdallocx (11,761,072 samples, 0.05%)free_fastpath (11,761,072 samples, 0.05%)core::ptr::drop_in_place<pgdog::backend::pool::connection::binding::Binding::read::{{closure}}> (4,234,317 samples, 0.02%)core::ptr::drop_in_place<pgdog::frontend::client::Client::buffer::{{closure}}> (45,529,507 samples, 0.19%)core::ptr::drop_in_place<pgdog::frontend::buffer::Buffer> (33,289,744 samples, 0.14%)tokio::runtime::task::waker::clone_waker (4,455,334 samples, 0.02%)core::ptr::drop_in_place<pgdog::frontend::client::Client::client_messages::{{closure}}> (17,304,968 samples, 0.07%)core::ptr::drop_in_place<pgdog::frontend::client::Client::server_message::{{closure}}> (4,657,145 samples, 0.02%)pgdog::frontend::buffer::Buffer::is_empty (4,881,763 samples, 0.02%)alloc::string::String::push (4,881,763 samples, 0.02%)alloc::vec::Vec<T,A>::push (4,881,763 samples, 0.02%)asm_sysvec_apic_timer_interrupt (4,868,275 samples, 0.02%)sysvec_apic_timer_interrupt (4,868,275 samples, 0.02%)__sysvec_apic_timer_interrupt (4,868,275 samples, 0.02%)hrtimer_interrupt (4,868,275 samples, 0.02%)__hrtimer_run_queues (4,868,275 samples, 0.02%)tick_nohz_handler (4,868,275 samples, 0.02%)update_process_times (4,868,275 samples, 0.02%)sched_tick (4,868,275 samples, 0.02%)perf_event_task_tick (4,868,275 samples, 0.02%)perf_adjust_freq_unthr_context (4,868,275 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::pool::connection::Connection::send<pgdog::backend::protocol::protocol_message::ProtocolMessage>::{{closure}}> (6,125,553 samples, 0.03%)[libc.so.6] (23,469,035 samples, 0.10%)lock_api::mutex::Mutex<R,T>::lock (14,895,268 samples, 0.06%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::lock (14,895,268 samples, 0.06%)core::ptr::drop_in_place<pgdog::frontend::client::inner::InnerBorrow> (45,668,252 samples, 0.19%)<pgdog::frontend::client::inner::InnerBorrow as core::ops::drop::Drop>::drop (45,668,252 samples, 0.19%)pgdog::frontend::comms::Comms::stats (22,199,217 samples, 0.09%)std::collections::hash::map::HashMap<K,V,S>::get_mut (4,973,001 samples, 0.02%)hashbrown::map::HashMap<K,V,S,A>::get_mut (4,973,001 samples, 0.02%)hashbrown::map::HashMap<K,V,S,A>::get_inner_mut (4,973,001 samples, 0.02%)hashbrown::map::make_hash (4,973,001 samples, 0.02%)core::hash::BuildHasher::hash_one (4,973,001 samples, 0.02%)core::hash::impls::<impl core::hash::Hash for &T>::hash (4,973,001 samples, 0.02%)<pgdog::net::messages::backend_key::BackendKeyData as core::hash::Hash>::hash (4,973,001 samples, 0.02%)core::hash::impls::<impl core::hash::Hash for i32>::hash (4,973,001 samples, 0.02%)core::hash::Hasher::write_i32 (4,973,001 samples, 0.02%)core::hash::Hasher::write_u32 (4,973,001 samples, 0.02%)<fnv::FnvHasher as core::hash::Hasher>::write (4,973,001 samples, 0.02%)core::num::<impl u64>::wrapping_mul (4,973,001 samples, 0.02%)core::ptr::drop_in_place<pgdog::frontend::router::parser::route::Route> (4,645,258 samples, 0.02%)pgdog::backend::pool::connection::Connection::send::_{{closure}} (4,451,922 samples, 0.02%)pgdog::frontend::client::inner::Inner::command (3,241,604 samples, 0.01%)core::option::Option<T>::map (3,241,604 samples, 0.01%)pgdog::frontend::client::inner::Inner::command::_{{closure}} (3,241,604 samples, 0.01%)pgdog::frontend::router::Router::query (3,241,604 samples, 0.01%)pgdog::frontend::router::parser::query::QueryParser::parse (3,241,604 samples, 0.01%)pgdog::frontend::buffer::Buffer::query (3,241,604 samples, 0.01%)std::sys::pal::unix::time::Timespec::now (3,241,604 samples, 0.01%)alloc::string::String::push (3,241,604 samples, 0.01%)alloc::vec::Vec<T,A>::push (3,241,604 samples, 0.01%)core::ptr::write (3,241,604 samples, 0.01%)[libc.so.6] (4,291,740 samples, 0.02%)pgdog::frontend::router::Router::route (7,374,372 samples, 0.03%)pgdog::frontend::router::parser::query::QueryParser::route (7,374,372 samples, 0.03%)<pgdog::net::messages::parse::Parse as core::clone::Clone>::clone (7,374,372 samples, 0.03%)<core::option::Option<T> as core::clone::Clone>::clone (7,374,372 samples, 0.03%)<bytes::bytes::Bytes as core::clone::Clone>::clone (7,374,372 samples, 0.03%)pgdog::net::stream::Stream::read::_{{closure}} (7,374,372 samples, 0.03%)pgdog::frontend::client::inner::Inner::connect::_{{closure}} (15,583,696 samples, 0.07%)pgdog::frontend::stats::Stats::connected (3,917,584 samples, 0.02%)std::time::Instant::now (3,917,584 samples, 0.02%)std::sys::pal::unix::time::Instant::now (3,917,584 samples, 0.02%)std::sys::pal::unix::time::Timespec::now (3,917,584 samples, 0.02%)clock_gettime (3,917,584 samples, 0.02%)[unknown] (3,917,584 samples, 0.02%)core::ptr::drop_in_place<tokio::time::sleep::Sleep> (3,917,584 samples, 0.02%)core::ptr::drop_in_place<tokio::runtime::time::entry::TimerEntry> (3,917,584 samples, 0.02%)[libc.so.6] (3,745,883 samples, 0.02%)pgdog::frontend::client::Client::client_messages::_{{closure}} (135,002,572 samples, 0.57%)tokio::time::timeout::timeout (9,109,277 samples, 0.04%)tokio::time::instant::Instant::now (5,363,394 samples, 0.02%)tokio::time::instant::variant::now (5,363,394 samples, 0.02%)std::time::Instant::now (5,363,394 samples, 0.02%)std::sys::pal::unix::time::Instant::now (5,363,394 samples, 0.02%)std::sys::pal::unix::time::Timespec::now (5,363,394 samples, 0.02%)clock_gettime (5,363,394 samples, 0.02%)pgdog::frontend::buffer::Buffer::len (5,363,394 samples, 0.02%)core::iter::traits::iterator::Iterator::sum (5,363,394 samples, 0.02%)<usize as core::iter::traits::accum::Sum>::sum (5,363,394 samples, 0.02%)<core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::fold (5,363,394 samples, 0.02%)<core::slice::iter::Iter<T> as core::iter::traits::iterator::Iterator>::fold (5,363,394 samples, 0.02%)core::iter::adapters::map::map_fold::_{{closure}} (5,363,394 samples, 0.02%)pgdog::frontend::buffer::Buffer::len::_{{closure}} (5,363,394 samples, 0.02%)pgdog::backend::protocol::protocol_message::ProtocolMessage::len (5,363,394 samples, 0.02%)<pgdog::net::messages::Message as pgdog::net::messages::Protocol>::code (3,012,137 samples, 0.01%)<tokio::net::tcp::stream::TcpStream as tokio::io::async_read::AsyncRead>::poll_read (6,143,008 samples, 0.03%)tokio::net::tcp::stream::TcpStream::poll_read_priv (6,143,008 samples, 0.03%)tokio::io::poll_evented::PollEvented<E>::poll_read (6,143,008 samples, 0.03%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read (6,143,008 samples, 0.03%)mio::io_source::IoSource<T>::do_io (6,143,008 samples, 0.03%)mio::sys::unix::selector::stateless_io_source::IoSourceState::do_io (6,143,008 samples, 0.03%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read::_{{closure}} (6,143,008 samples, 0.03%)<&std::net::tcp::TcpStream as std::io::Read>::read (6,143,008 samples, 0.03%)std::sys::net::connection::socket::TcpStream::read (6,143,008 samples, 0.03%)std::sys::net::connection::socket::unix::Socket::read (6,143,008 samples, 0.03%)std::sys::net::connection::socket::unix::Socket::recv_with_flags (6,143,008 samples, 0.03%)std::sys::pal::unix::cvt (6,143,008 samples, 0.03%)<isize as std::sys::pal::unix::IsMinusOne>::is_minus_one (6,143,008 samples, 0.03%)[libc.so.6] (22,063,878 samples, 0.09%)[libc.so.6] (4,861,013 samples, 0.02%)core::intrinsics::likely (3,964,317 samples, 0.02%)hashbrown::control::group::sse2::Group::match_tag (4,341,901 samples, 0.02%)core::core_arch::x86::sse2::_mm_movemask_epi8 (4,341,901 samples, 0.02%)hashbrown::control::tag::Tag::full (7,355,737 samples, 0.03%)core::ptr::drop_in_place<pgdog::frontend::client::inner::InnerBorrow> (47,639,476 samples, 0.20%)<pgdog::frontend::client::inner::InnerBorrow as core::ops::drop::Drop>::drop (47,639,476 samples, 0.20%)pgdog::frontend::comms::Comms::stats (25,575,598 samples, 0.11%)std::collections::hash::map::HashMap<K,V,S>::get_mut (20,714,585 samples, 0.09%)hashbrown::map::HashMap<K,V,S,A>::get_mut (20,714,585 samples, 0.09%)hashbrown::map::HashMap<K,V,S,A>::get_inner_mut (20,714,585 samples, 0.09%)hashbrown::raw::RawTable<T,A>::get_mut (15,661,971 samples, 0.07%)hashbrown::raw::RawTable<T,A>::find (15,661,971 samples, 0.07%)hashbrown::raw::RawTableInner::find_inner (15,661,971 samples, 0.07%)_rjem_sdallocx (4,133,798 samples, 0.02%)free_fastpath (4,133,798 samples, 0.02%)core::ptr::drop_in_place<pgdog::net::messages::Message> (11,379,161 samples, 0.05%)core::ptr::drop_in_place<bytes::bytes::Bytes> (11,379,161 samples, 0.05%)<bytes::bytes::Bytes as core::ops::drop::Drop>::drop (11,379,161 samples, 0.05%)bytes::bytes::promotable_even_drop (7,245,363 samples, 0.03%)<core::sync::atomic::AtomicPtr<T> as bytes::loom::sync::atomic::AtomicMut<T>>::with_mut (7,245,363 samples, 0.03%)core::ptr::drop_in_place<pgdog::net::parameter::Parameters> (7,649,880 samples, 0.03%)core::ptr::drop_in_place<std::collections::hash::map::HashMap<alloc::string::String,alloc::string::String>> (7,649,880 samples, 0.03%)core::ptr::drop_in_place<hashbrown::map::HashMap<alloc::string::String,alloc::string::String,std::hash::random::RandomState>> (7,649,880 samples, 0.03%)core::ptr::drop_in_place<hashbrown::raw::RawTable<(alloc::string::String,alloc::string::String)>> (7,649,880 samples, 0.03%)<hashbrown::raw::RawTable<T,A> as core::ops::drop::Drop>::drop (7,649,880 samples, 0.03%)hashbrown::raw::RawTableInner::drop_inner_table (7,649,880 samples, 0.03%)hashbrown::raw::RawTableInner::free_buckets (7,649,880 samples, 0.03%)<alloc::alloc::Global as core::alloc::Allocator>::deallocate (7,649,880 samples, 0.03%)alloc::alloc::dealloc (7,649,880 samples, 0.03%)__rust_dealloc (7,649,880 samples, 0.03%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::dealloc (7,649,880 samples, 0.03%)_rjem_sdallocx (7,649,880 samples, 0.03%)free_fastpath (7,649,880 samples, 0.03%)core::ptr::drop_in_place<pgdog::net::stream::Stream::send<pgdog::net::messages::Message>::{{closure}}> (4,389,392 samples, 0.02%)<hashbrown::raw::RawTable<T,A> as hashbrown::raw::RawTableClone>::clone_from_spec (4,456,865 samples, 0.02%)hashbrown::raw::RawTable<T,A>::clone_from_impl (4,456,865 samples, 0.02%)core::ptr::mut_ptr::<impl *mut T>::copy_to_nonoverlapping (4,456,865 samples, 0.02%)core::intrinsics::copy_nonoverlapping (4,456,865 samples, 0.02%)[libc.so.6] (4,456,865 samples, 0.02%)hashbrown::raw::TableLayout::calculate_layout_for (5,368,242 samples, 0.02%)core::num::<impl usize>::checked_mul (5,368,242 samples, 0.02%)pgdog::backend::pool::connection::Connection::changed_params (53,035,998 samples, 0.22%)pgdog::backend::pool::connection::binding::Binding::changed_params (53,035,998 samples, 0.22%)<pgdog::net::parameter::Parameters as core::clone::Clone>::clone (53,035,998 samples, 0.22%)<std::collections::hash::map::HashMap<K,V,S> as core::clone::Clone>::clone (53,035,998 samples, 0.22%)<hashbrown::map::HashMap<K,V,S,A> as core::clone::Clone>::clone (49,089,002 samples, 0.21%)<hashbrown::raw::RawTable<T,A> as core::clone::Clone>::clone (43,764,113 samples, 0.18%)hashbrown::raw::RawTable<T,A>::new_uninitialized (39,307,248 samples, 0.17%)hashbrown::raw::RawTableInner::new_uninitialized (39,307,248 samples, 0.17%)hashbrown::raw::alloc::inner::do_alloc (33,939,006 samples, 0.14%)<alloc::alloc::Global as core::alloc::Allocator>::allocate (33,939,006 samples, 0.14%)alloc::alloc::Global::alloc_impl (33,939,006 samples, 0.14%)alloc::alloc::alloc (33,939,006 samples, 0.14%)__rust_alloc (33,939,006 samples, 0.14%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::alloc (33,939,006 samples, 0.14%)_rjem_malloc (29,734,269 samples, 0.13%)imalloc_fastpath (29,734,269 samples, 0.13%)cache_bin_alloc_easy (11,793,262 samples, 0.05%)cache_bin_alloc_impl (11,793,262 samples, 0.05%)pgdog::backend::pool::connection::Connection::done (14,304,223 samples, 0.06%)pgdog::backend::pool::connection::binding::Binding::done (14,304,223 samples, 0.06%)pgdog::frontend::client::inner::Inner::disconnect (27,652,072 samples, 0.12%)pgdog::backend::pool::connection::Connection::disconnect (27,652,072 samples, 0.12%)pgdog::backend::pool::connection::binding::Binding::disconnect (27,652,072 samples, 0.12%)core::mem::drop (10,727,498 samples, 0.05%)core::ptr::drop_in_place<core::option::Option<pgdog::backend::pool::guard::Guard>> (10,727,498 samples, 0.05%)core::ptr::drop_in_place<pgdog::backend::pool::guard::Guard> (7,515,321 samples, 0.03%)<pgdog::backend::pool::guard::Guard as core::ops::drop::Drop>::drop (4,517,736 samples, 0.02%)pgdog::backend::pool::guard::Guard::cleanup (4,517,736 samples, 0.02%)core::option::Option<T>::take (4,517,736 samples, 0.02%)core::mem::replace (4,517,736 samples, 0.02%)core::ptr::read (4,517,736 samples, 0.02%)core::ptr::drop_in_place<pgdog::frontend::router::parser::command::Command> (2,581,291 samples, 0.01%)pgdog::frontend::client::inner::Inner::reset_router (11,776,274 samples, 0.05%)pgdog::frontend::router::Router::reset (11,776,274 samples, 0.05%)pgdog::frontend::router::parser::query::QueryParser::reset (11,776,274 samples, 0.05%)core::ptr::drop_in_place<pgdog::frontend::router::parser::route::Route> (9,194,983 samples, 0.04%)core::ptr::drop_in_place<pgdog::frontend::router::parser::aggregate::Aggregate> (4,888,798 samples, 0.02%)core::ptr::drop_in_place<alloc::vec::Vec<usize>> (4,888,798 samples, 0.02%)core::ptr::drop_in_place<alloc::raw_vec::RawVec<usize>> (4,888,798 samples, 0.02%)<alloc::raw_vec::RawVec<T,A> as core::ops::drop::Drop>::drop (4,888,798 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::deallocate (4,888,798 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::current_memory (4,888,798 samples, 0.02%)core::option::Option<T>::as_ref (4,411,188 samples, 0.02%)pgdog::frontend::client::inner::Inner::transaction_mode (24,983,210 samples, 0.11%)pgdog::backend::pool::connection::Connection::transaction_mode (24,983,210 samples, 0.11%)pgdog::backend::pool::connection::Connection::cluster (24,983,210 samples, 0.11%)core::option::Option<T>::ok_or (20,572,022 samples, 0.09%)core::ptr::drop_in_place<pgdog::backend::error::Error> (20,572,022 samples, 0.09%)[unknown] (6,632,711 samples, 0.03%)[libc.so.6] (6,632,711 samples, 0.03%)<pgdog::net::messages::command_complete::CommandComplete as pgdog::net::messages::FromBytes>::from_bytes (5,162,047 samples, 0.02%)pgdog::frontend::stats::Stats::query (17,753,708 samples, 0.07%)std::time::Instant::now (17,753,708 samples, 0.07%)std::sys::pal::unix::time::Instant::now (17,753,708 samples, 0.07%)std::sys::pal::unix::time::Timespec::now (11,120,997 samples, 0.05%)clock_gettime (11,120,997 samples, 0.05%)[unknown] (11,120,997 samples, 0.05%)pgdog::backend::server::Server::read::_{{closure}} (5,958,950 samples, 0.03%)clock_gettime (17,282,289 samples, 0.07%)__vdso_clock_gettime (17,282,289 samples, 0.07%)pgdog::frontend::stats::Stats::transaction (23,992,967 samples, 0.10%)std::time::Instant::elapsed (23,992,967 samples, 0.10%)std::time::Instant::now (23,992,967 samples, 0.10%)std::sys::pal::unix::time::Instant::now (23,992,967 samples, 0.10%)std::sys::pal::unix::time::Timespec::now (23,992,967 samples, 0.10%)core::result::Result<T,E>::unwrap (6,710,678 samples, 0.03%)pgdog::net::messages::Message::backend (2,403,438 samples, 0.01%)<core::result::Result<T,E> as core::ops::try_trait::Try>::branch (5,063,455 samples, 0.02%)<pgdog::net::messages::Message as pgdog::net::messages::ToBytes>::to_bytes (39,611,115 samples, 0.17%)<bytes::bytes::Bytes as core::clone::Clone>::clone (39,611,115 samples, 0.17%)bytes::bytes::promotable_even_clone (39,611,115 samples, 0.17%)bytes::bytes::shallow_clone_vec (35,218,506 samples, 0.15%)alloc::boxed::Box<T>::new (14,783,188 samples, 0.06%)alloc::alloc::exchange_malloc (14,783,188 samples, 0.06%)<alloc::alloc::Global as core::alloc::Allocator>::allocate (14,783,188 samples, 0.06%)alloc::alloc::Global::alloc_impl (14,783,188 samples, 0.06%)alloc::alloc::alloc (14,783,188 samples, 0.06%)__rust_alloc (14,783,188 samples, 0.06%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::alloc (14,783,188 samples, 0.06%)_rjem_malloc (14,783,188 samples, 0.06%)imalloc_fastpath (14,783,188 samples, 0.06%)cache_bin_alloc_easy (5,070,589 samples, 0.02%)cache_bin_alloc_impl (5,070,589 samples, 0.02%)<tokio::io::util::write_all::WriteAll<W> as core::future::future::Future>::poll (14,217,514 samples, 0.06%)<&mut T as tokio::io::async_write::AsyncWrite>::poll_write (5,016,881 samples, 0.02%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_write::AsyncWrite>::poll_write (5,016,881 samples, 0.02%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_write::AsyncWrite>::poll_write (5,016,881 samples, 0.02%)<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_write::AsyncWrite>::poll_write (5,016,881 samples, 0.02%)pgdog::net::stream::Stream::send::_{{closure}} (76,357,355 samples, 0.32%)core::ptr::drop_in_place<bytes::bytes::Bytes> (3,714,092 samples, 0.02%)<bytes::bytes::Bytes as core::ops::drop::Drop>::drop (3,714,092 samples, 0.02%)bytes::bytes::shared_drop (3,714,092 samples, 0.02%)<core::sync::atomic::AtomicPtr<T> as bytes::loom::sync::atomic::AtomicMut<T>>::with_mut (3,714,092 samples, 0.02%)bytes::bytes::shared_drop::_{{closure}} (3,714,092 samples, 0.02%)<tracing_core::metadata::Level as core::cmp::PartialOrd<tracing_core::metadata::LevelFilter>>::le (29,349,051 samples, 0.12%)__x86_indirect_thunk_array (3,864,079 samples, 0.02%)fput (11,613,602 samples, 0.05%)__local_bh_enable_ip (8,608,383 samples, 0.04%)release_sock (19,799,904 samples, 0.08%)_raw_spin_lock_bh (10,734,584 samples, 0.05%)__check_object_size (21,925,531 samples, 0.09%)__virt_addr_valid (12,929,808 samples, 0.05%)__ip_finish_output (52,209,989 samples, 0.22%)ip_skb_dst_mtu (39,610,302 samples, 0.17%)__rcu_read_lock (2,892,608 samples, 0.01%)__rcu_read_unlock (18,865,877 samples, 0.08%)ipv4_dst_check (16,399,222 samples, 0.07%)__rcu_read_unlock (4,485,332 samples, 0.02%)__sk_dst_check (33,189,506 samples, 0.14%)srso_alias_return_thunk (5,986,029 samples, 0.03%)srso_alias_safe_ret (5,986,029 samples, 0.03%)ip_finish_output (10,538,300 samples, 0.04%)irqtime_account_irq (110,604,703 samples, 0.47%)sched_clock_cpu (63,605,251 samples, 0.27%)sched_clock (39,263,105 samples, 0.17%)native_sched_clock (39,263,105 samples, 0.17%)__netif_receive_skb (7,328,882 samples, 0.03%)__netif_receive_skb_core.constprop.0 (37,182,674 samples, 0.16%)__rcu_read_unlock (4,049,906 samples, 0.02%)raw_local_deliver (28,010,783 samples, 0.12%)__inet_lookup_established (45,527,934 samples, 0.19%)__xfrm_policy_check2.constprop.0 (6,149,709 samples, 0.03%)_raw_spin_unlock (8,175,508 samples, 0.03%)asm_sysvec_apic_timer_interrupt (2,956,581 samples, 0.01%)sysvec_apic_timer_interrupt (2,956,581 samples, 0.01%)__sysvec_apic_timer_interrupt (2,956,581 samples, 0.01%)hrtimer_interrupt (2,956,581 samples, 0.01%)__hrtimer_run_queues (2,956,581 samples, 0.01%)tick_nohz_handler (2,956,581 samples, 0.01%)update_process_times (2,956,581 samples, 0.01%)sched_tick (2,956,581 samples, 0.01%)psi_account_irqtime (2,956,581 samples, 0.01%)__rcu_read_lock (5,722,278 samples, 0.02%)__rcu_read_unlock (4,949,201 samples, 0.02%)sk_filter_trim_cap (54,020,305 samples, 0.23%)security_sock_rcv_skb (12,739,153 samples, 0.05%)sock_put (3,373,156 samples, 0.01%)srso_alias_return_thunk (4,592,715 samples, 0.02%)srso_alias_safe_ret (4,592,715 samples, 0.02%)tcp_inbound_hash (28,241,668 samples, 0.12%)tcp_do_parse_auth_options (5,089,246 samples, 0.02%)srso_alias_return_thunk (5,925,581 samples, 0.03%)srso_alias_safe_ret (5,925,581 samples, 0.03%)__rcu_read_unlock (4,696,153 samples, 0.02%)sk_reset_timer (35,264,144 samples, 0.15%)__mod_timer (25,473,973 samples, 0.11%)enqueue_timer (9,158,609 samples, 0.04%)default_wake_function (6,509,441 samples, 0.03%)_raw_spin_lock_irqsave (7,221,267 samples, 0.03%)available_idle_cpu (14,565,382 samples, 0.06%)select_task_rq_fair (46,556,783 samples, 0.20%)select_idle_core.isra.0 (5,816,214 samples, 0.02%)available_idle_cpu (5,816,214 samples, 0.02%)srso_alias_return_thunk (4,945,963 samples, 0.02%)srso_alias_safe_ret (4,945,963 samples, 0.02%)srso_alias_safe_ret (4,404,648 samples, 0.02%)call_function_single_prep_ipi (18,608,604 samples, 0.08%)__smp_call_single_queue (55,144,881 samples, 0.23%)llist_add_batch (31,736,856 samples, 0.13%)__default_send_IPI_dest_field (53,288,347 samples, 0.22%)default_send_IPI_single_phys (66,960,601 samples, 0.28%)native_send_call_func_single_ipi (4,077,844 samples, 0.02%)__wake_up_common (297,952,729 samples, 1.26%)pollwake (255,880,674 samples, 1.08%)try_to_wake_up (237,987,838 samples, 1.00%)ttwu_queue_wakelist (145,001,930 samples, 0.61%)sched_clock_cpu (4,860,242 samples, 0.02%)sched_clock (4,860,242 samples, 0.02%)native_sched_clock (4,860,242 samples, 0.02%)__wake_up_sync_key (307,765,638 samples, 1.30%)_raw_spin_lock_irqsave (3,844,075 samples, 0.02%)sock_def_readable (348,925,676 samples, 1.47%)_raw_spin_unlock_irqrestore (16,042,905 samples, 0.07%)kmem_cache_free (26,523,394 samples, 0.11%)__slab_free (17,722,996 samples, 0.07%)slab_update_freelist.isra.0 (4,643,177 samples, 0.02%)skb_release_data (41,671,622 samples, 0.18%)srso_alias_return_thunk (4,206,027 samples, 0.02%)srso_alias_safe_ret (4,206,027 samples, 0.02%)__kfree_skb (49,684,546 samples, 0.21%)srso_alias_return_thunk (3,782,932 samples, 0.02%)srso_alias_safe_ret (3,782,932 samples, 0.02%)cubictcp_acked (4,401,830 samples, 0.02%)kfree_skbmem (7,410,083 samples, 0.03%)kmem_cache_free (10,294,649 samples, 0.04%)__slab_free (3,483,423 samples, 0.01%)rb_first (4,656,855 samples, 0.02%)srso_alias_return_thunk (17,809,562 samples, 0.08%)srso_alias_safe_ret (9,327,655 samples, 0.04%)tcp_ack_update_rtt (43,790,591 samples, 0.18%)srso_alias_return_thunk (3,803,730 samples, 0.02%)srso_alias_safe_ret (3,803,730 samples, 0.02%)tcp_newly_delivered (9,769,358 samples, 0.04%)tcp_rack_advance (17,632,534 samples, 0.07%)tcp_rack_update_reo_wnd (6,367,608 samples, 0.03%)tcp_rate_gen (9,929,355 samples, 0.04%)tcp_rate_skb_delivered (3,599,898 samples, 0.02%)tcp_schedule_loss_probe (5,932,360 samples, 0.03%)tcp_schedule_loss_probe.part.0 (13,057,232 samples, 0.06%)tcp_update_pacing_rate (3,848,910 samples, 0.02%)tcp_ack (363,259,879 samples, 1.53%)tcp_xmit_recovery (8,729,169 samples, 0.04%)tcp_check_space (8,700,407 samples, 0.04%)tcp_data_ready (3,936,436 samples, 0.02%)tcp_event_data_recv (35,651,198 samples, 0.15%)tcp_mstamp_refresh (23,036,318 samples, 0.10%)ktime_get (5,527,762 samples, 0.02%)read_tsc (5,527,762 samples, 0.02%)tcp_v4_do_rcv (976,737,310 samples, 4.12%)tcp_..tcp_rcv_established (948,927,171 samples, 4.01%)tcp_..tcp_queue_rcv (20,756,317 samples, 0.09%)ip_protocol_deliver_rcu (1,275,472,740 samples, 5.38%)ip_prot..tcp_v4_rcv (1,218,749,727 samples, 5.15%)tcp_v4..tcp_v4_fill_cb (8,688,515 samples, 0.04%)ip_local_deliver_finish (1,338,564,337 samples, 5.65%)ip_loca..ktime_get_with_offset (29,732,022 samples, 0.13%)read_tsc (12,124,497 samples, 0.05%)ip_rcv_core (17,494,628 samples, 0.07%)asm_sysvec_apic_timer_interrupt (3,746,250 samples, 0.02%)sysvec_apic_timer_interrupt (3,746,250 samples, 0.02%)__sysvec_apic_timer_interrupt (3,746,250 samples, 0.02%)hrtimer_interrupt (3,746,250 samples, 0.02%)__hrtimer_run_queues (3,746,250 samples, 0.02%)tick_nohz_handler (3,746,250 samples, 0.02%)update_process_times (3,746,250 samples, 0.02%)sched_tick (3,746,250 samples, 0.02%)raw_spin_rq_lock_nested (3,746,250 samples, 0.02%)_raw_spin_lock (3,746,250 samples, 0.02%)ip_rcv (66,469,905 samples, 0.28%)ip_rcv_finish_core (32,569,924 samples, 0.14%)__netif_receive_skb_one_core (1,466,613,413 samples, 6.19%)__netif_..srso_alias_return_thunk (4,452,561 samples, 0.02%)srso_alias_safe_ret (4,452,561 samples, 0.02%)__napi_poll (1,569,943,788 samples, 6.63%)__napi_po..process_backlog (1,554,744,432 samples, 6.56%)process_b.._raw_spin_lock_irq (37,811,317 samples, 0.16%)kfree_skbmem (10,052,084 samples, 0.04%)kmem_cache_free (17,969,383 samples, 0.08%)asm_sysvec_apic_timer_interrupt (2,578,346 samples, 0.01%)sysvec_apic_timer_interrupt (2,578,346 samples, 0.01%)__sysvec_apic_timer_interrupt (2,578,346 samples, 0.01%)hrtimer_interrupt (2,578,346 samples, 0.01%)__hrtimer_run_queues (2,578,346 samples, 0.01%)tick_nohz_handler (2,578,346 samples, 0.01%)update_process_times (2,578,346 samples, 0.01%)rcu_sched_clock_irq (2,578,346 samples, 0.01%)free_frozen_pages (4,294,962 samples, 0.02%)free_frozen_page_commit (4,294,962 samples, 0.02%)free_pcppages_bulk (4,294,962 samples, 0.02%)__free_one_page (4,294,962 samples, 0.02%)kmem_cache_free (17,997,561 samples, 0.08%)skb_release_data (39,912,508 samples, 0.17%)skb_free_head (3,964,890 samples, 0.02%)napi_consume_skb (62,146,625 samples, 0.26%)skb_release_head_state (4,491,826 samples, 0.02%)__local_bh_enable_ip (1,963,575,677 samples, 8.29%)__local_bh_e..do_softirq.part.0 (1,938,053,542 samples, 8.18%)do_softirq...handle_softirqs (1,917,530,177 samples, 8.10%)handle_soft..net_rx_action (1,748,128,569 samples, 7.38%)net_rx_act..srso_alias_safe_ret (4,582,681 samples, 0.02%)raise_softirq_irqoff (13,271,141 samples, 0.06%)__netif_rx (32,381,814 samples, 0.14%)netif_rx_internal (28,375,373 samples, 0.12%)enqueue_to_backlog (28,375,373 samples, 0.12%)srso_alias_return_thunk (5,091,640 samples, 0.02%)eth_type_trans (14,222,759 samples, 0.06%)sk_free (4,120,457 samples, 0.02%)dev_hard_start_xmit (91,558,915 samples, 0.39%)loopback_xmit (91,558,915 samples, 0.39%)skb_clone_tx_timestamp (18,170,374 samples, 0.08%)netif_skb_features (4,706,872 samples, 0.02%)validate_xmit_skb (23,918,206 samples, 0.10%)skb_csum_hwoffload_help (3,963,720 samples, 0.02%)ip_finish_output2 (2,160,182,806 samples, 9.12%)ip_finish_out..__dev_queue_xmit (2,113,314,451 samples, 8.92%)__dev_queue_x..validate_xmit_xfrm (7,258,803 samples, 0.03%)ip_local_out (19,191,614 samples, 0.08%)__ip_local_out (12,731,382 samples, 0.05%)ip_send_check (12,731,366 samples, 0.05%)ip_output (4,133,798 samples, 0.02%)__ip_queue_xmit (2,393,371,673 samples, 10.10%)__ip_queue_xmitsrso_alias_return_thunk (4,899,211 samples, 0.02%)srso_alias_safe_ret (4,899,211 samples, 0.02%)__skb_clone (19,801,059 samples, 0.08%)__tcp_select_window (3,568,408 samples, 0.02%)bpf_skops_write_hdr_opt.isra.0 (13,154,588 samples, 0.06%)cubictcp_cwnd_event (3,288,194 samples, 0.01%)ip_queue_xmit (3,907,542 samples, 0.02%)skb_clone (9,525,931 samples, 0.04%)skb_push (5,502,929 samples, 0.02%)srso_alias_return_thunk (3,885,861 samples, 0.02%)tcp_established_options (5,901,874 samples, 0.02%)tcp_rate_skb_sent (18,207,349 samples, 0.08%)tcp_update_skb_after_send (5,139,523 samples, 0.02%)__tcp_transmit_skb (2,656,559,491 samples, 11.22%)__tcp_transmit_skbtcp_v4_send_check (12,091,437 samples, 0.05%)ktime_get (17,323,855 samples, 0.07%)read_tsc (12,052,455 samples, 0.05%)tcp_chrono_stop (5,225,736 samples, 0.02%)rb_insert_color (4,382,647 samples, 0.02%)sk_reset_timer (31,016,354 samples, 0.13%)__mod_timer (21,839,555 samples, 0.09%)tcp_rbtree_insert (14,294,906 samples, 0.06%)tcp_event_new_data_sent (79,293,199 samples, 0.33%)tcp_rearm_rto (4,686,313 samples, 0.02%)__usecs_to_jiffies (10,043,382 samples, 0.04%)rb_first (4,360,167 samples, 0.02%)tcp_schedule_loss_probe.part.0 (116,703,592 samples, 0.49%)sk_reset_timer (4,515,255 samples, 0.02%)__tcp_push_pending_frames (2,917,734,059 samples, 12.32%)__tcp_push_pending..tcp_write_xmit (2,917,734,059 samples, 12.32%)tcp_write_xmit_copy_from_iter (3,627,556 samples, 0.02%)asm_common_interrupt (3,546,511 samples, 0.01%)common_interrupt (3,546,511 samples, 0.01%)__common_interrupt (3,546,511 samples, 0.01%)handle_edge_irq (3,546,511 samples, 0.01%)handle_irq_event (3,546,511 samples, 0.01%)__handle_irq_event_percpu (3,546,511 samples, 0.01%)[[nvidia]] (3,546,511 samples, 0.01%)[[nvidia]] (3,546,511 samples, 0.01%)[[nvidia]] (3,546,511 samples, 0.01%)[[nvidia]] (3,546,511 samples, 0.01%)[[nvidia]] (3,546,511 samples, 0.01%)[[nvidia]] (3,546,511 samples, 0.01%)[[nvidia]] (3,546,511 samples, 0.01%)[[nvidia]] (3,546,511 samples, 0.01%)[[nvidia]] (3,546,511 samples, 0.01%)[[nvidia]] (3,546,511 samples, 0.01%)__wake_up (3,546,511 samples, 0.01%)__wake_up_common (3,546,511 samples, 0.01%)ep_poll_callback (3,546,511 samples, 0.01%)__wake_up (3,546,511 samples, 0.01%)__wake_up_common (3,546,511 samples, 0.01%)ep_autoremove_wake_function (3,546,511 samples, 0.01%)try_to_wake_up (3,546,511 samples, 0.01%)select_task_rq_fair (3,546,511 samples, 0.01%)tcp_push (4,341,869 samples, 0.02%)tcp_skb_entail (3,714,063 samples, 0.02%)__alloc_skb (5,869,990 samples, 0.02%)kmalloc_reserve (5,869,990 samples, 0.02%)kmem_cache_alloc_node_noprof (5,869,990 samples, 0.02%)__x64_sys_sendto (3,067,931,094 samples, 12.95%)__x64_sys_sendto__sys_sendto (3,062,116,868 samples, 12.93%)__sys_sendtotcp_sendmsg (3,017,980,242 samples, 12.74%)tcp_sendmsgtcp_sendmsg_locked (2,979,117,784 samples, 12.58%)tcp_sendmsg_lockedtcp_stream_alloc_skb (9,465,457 samples, 0.04%)sk_forced_mem_schedule (3,595,467 samples, 0.02%)asm_sysvec_apic_timer_interrupt (4,507,299 samples, 0.02%)sysvec_apic_timer_interrupt (4,507,299 samples, 0.02%)__sysvec_apic_timer_interrupt (4,507,299 samples, 0.02%)hrtimer_interrupt (4,507,299 samples, 0.02%)__hrtimer_run_queues (4,507,299 samples, 0.02%)tick_nohz_handler (4,507,299 samples, 0.02%)update_process_times (4,507,299 samples, 0.02%)sched_tick (4,507,299 samples, 0.02%)task_tick_fair (4,507,299 samples, 0.02%)update_load_avg (4,507,299 samples, 0.02%)entry_SYSCALL_64_after_hwframe (3,137,333,118 samples, 13.25%)entry_SYSCALL_64_aft..do_syscall_64 (3,129,494,731 samples, 13.21%)do_syscall_64syscall_exit_to_user_mode (8,413,646 samples, 0.04%)__send (3,184,459,292 samples, 13.44%)__send[libc.so.6] (3,174,598,665 samples, 13.40%)[libc.so.6][libc.so.6] (3,163,140,955 samples, 13.35%)[libc.so.6][libc.so.6] (3,149,447,841 samples, 13.30%)[libc.so.6]syscall_return_via_sysret (8,250,644 samples, 0.03%)tokio::io::util::buf_writer::BufWriter<W>::flush_buf (3,206,156,189 samples, 13.54%)tokio::io::util::buf..<tokio::net::tcp::stream::TcpStream as tokio::io::async_write::AsyncWrite>::poll_write (3,197,550,071 samples, 13.50%)<tokio::net::tcp::st..tokio::net::tcp::stream::TcpStream::poll_write_priv (3,197,550,071 samples, 13.50%)tokio::net::tcp::str..tokio::io::poll_evented::PollEvented<E>::poll_write (3,197,550,071 samples, 13.50%)tokio::io::poll_even..<&mio::net::tcp::stream::TcpStream as std::io::Write>::write (3,194,043,100 samples, 13.48%)<&mio::net::tcp::str..mio::io_source::IoSource<T>::do_io (3,194,043,100 samples, 13.48%)mio::io_source::IoSo..mio::sys::unix::selector::stateless_io_source::IoSourceState::do_io (3,194,043,100 samples, 13.48%)mio::sys::unix::sele..<&mio::net::tcp::stream::TcpStream as std::io::Write>::write::_{{closure}} (3,194,043,100 samples, 13.48%)<&mio::net::tcp::str..<&std::net::tcp::TcpStream as std::io::Write>::write (3,194,043,100 samples, 13.48%)<&std::net::tcp::Tcp..std::sys::net::connection::socket::TcpStream::write (3,194,043,100 samples, 13.48%)std::sys::net::conne..std::sys::pal::unix::cvt (8,823,301 samples, 0.04%)pgdog::frontend::client::Client::server_message::_{{closure}} (3,639,512,698 samples, 15.37%)pgdog::frontend::client:..pgdog::net::stream::Stream::send_flush::_{{closure}} (3,239,998,943 samples, 13.68%)pgdog::net::stream::S..tracing_core::metadata::LevelFilter::current (4,493,703 samples, 0.02%)core::sync::atomic::AtomicUsize::load (4,493,703 samples, 0.02%)core::sync::atomic::atomic_load (4,493,703 samples, 0.02%)pgdog::net::c_string_buf (2,577,178 samples, 0.01%)bytes::buf::buf_impl::Buf::get_u8 (2,577,178 samples, 0.01%)pgdog::net::stream::Stream::send::_{{closure}} (4,495,525 samples, 0.02%)core::ptr::drop_in_place<bytes::bytes::Bytes> (4,495,525 samples, 0.02%)<bytes::bytes::Bytes as core::ops::drop::Drop>::drop (4,495,525 samples, 0.02%)<tokio::sync::notify::Notified as core::ops::drop::Drop>::drop (4,495,525 samples, 0.02%)[unknown] (7,094,195 samples, 0.03%)bytes::bytes::shared_drop (7,094,195 samples, 0.03%)<core::sync::atomic::AtomicPtr<T> as bytes::loom::sync::atomic::AtomicMut<T>>::with_mut (7,094,195 samples, 0.03%)bytes::bytes::shared_drop::_{{closure}} (7,094,195 samples, 0.03%)bytes::bytes::release_shared (7,094,195 samples, 0.03%)tokio::time::instant::Instant::now (115,758,445 samples, 0.49%)tokio::time::instant::variant::now (115,758,445 samples, 0.49%)std::time::Instant::now (115,758,445 samples, 0.49%)std::sys::pal::unix::time::Instant::now (115,758,445 samples, 0.49%)std::sys::pal::unix::time::Timespec::now (111,262,920 samples, 0.47%)clock_gettime (111,262,920 samples, 0.47%)__vdso_clock_gettime (79,291,494 samples, 0.33%)tokio::time::sleep::Sleep::far_future (15,166,550 samples, 0.06%)tokio::time::instant::Instant::far_future (15,166,550 samples, 0.06%)tokio::time::instant::Instant::now (15,166,550 samples, 0.06%)tokio::time::instant::variant::now (15,166,550 samples, 0.06%)std::time::Instant::now (15,166,550 samples, 0.06%)std::sys::pal::unix::time::Instant::now (15,166,550 samples, 0.06%)std::sys::pal::unix::time::Timespec::now (15,166,550 samples, 0.06%)clock_gettime (15,166,550 samples, 0.06%)__vdso_clock_gettime (15,166,550 samples, 0.06%)core::ops::function::FnOnce::call_once (4,738,766 samples, 0.02%)tokio::runtime::context::CONTEXT::_{{constant}}::_{{closure}} (4,738,766 samples, 0.02%)std::sys::thread_local::native::eager::Storage<T>::get (4,738,766 samples, 0.02%)core::cell::Cell<T>::get (4,738,766 samples, 0.02%)pgdog::frontend::client::Client::spawn_internal::_{{closure}} (6,651,362,982 samples, 28.08%)pgdog::frontend::client::Client::spawn_intern..pgdog::frontend::client::Client::run::_{{closure}} (6,621,640,265 samples, 27.96%)pgdog::frontend::client::Client::run::_{{clos..tokio::time::timeout::timeout (160,295,893 samples, 0.68%)tokio::time::sleep::Sleep::new_timeout (15,279,763 samples, 0.06%)tokio::runtime::scheduler::Handle::current (15,279,763 samples, 0.06%)tokio::runtime::context::current::with_current (15,279,763 samples, 0.06%)std::thread::local::LocalKey<T>::try_with (15,279,763 samples, 0.06%)tokio::runtime::context::current::with_current::_{{closure}} (10,540,997 samples, 0.04%)core::option::Option<T>::map (10,540,997 samples, 0.04%)core::ops::function::FnOnce::call_once (10,540,997 samples, 0.04%)<tokio::runtime::scheduler::Handle as core::clone::Clone>::clone (10,540,997 samples, 0.04%)tokio::runtime::task::harness::poll_future (6,807,291,708 samples, 28.74%)tokio::runtime::task::harness::poll_futurestd::panic::catch_unwind (6,807,291,708 samples, 28.74%)std::panic::catch_unwindstd::panicking::try (6,807,291,708 samples, 28.74%)std::panicking::trystd::panicking::try::do_call (6,807,291,708 samples, 28.74%)std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once (6,807,291,708 samples, 28.74%)<core::panic::unwind_safe::AssertUnwindSafe<F>..tokio::runtime::task::harness::poll_future::_{{closure}} (6,807,291,708 samples, 28.74%)tokio::runtime::task::harness::poll_future::_{..tokio::runtime::task::core::Core<T,S>::poll (6,807,291,708 samples, 28.74%)tokio::runtime::task::core::Core<T,S>::polltokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut (6,807,291,708 samples, 28.74%)tokio::loom::std::unsafe_cell::UnsafeCell<T>::..tokio::runtime::task::core::Core<T,S>::poll::_{{closure}} (6,807,291,708 samples, 28.74%)tokio::runtime::task::core::Core<T,S>::poll::_..<tokio_util::task::task_tracker::TrackedFuture<F> as core::future::future::Future>::poll (6,801,670,328 samples, 28.72%)<tokio_util::task::task_tracker::TrackedFuture..pgdog::frontend::listener::Listener::listen::_{{closure}}::_{{closure}} (6,801,670,328 samples, 28.72%)pgdog::frontend::listener::Listener::listen::_..pgdog::frontend::listener::Listener::handle_client::_{{closure}} (6,750,030,775 samples, 28.50%)pgdog::frontend::listener::Listener::handle_cl..pgdog::frontend::client::Client::spawn::_{{closure}} (6,737,206,651 samples, 28.44%)pgdog::frontend::client::Client::spawn::_{{clo..tokio::runtime::scheduler::multi_thread::worker::Context::run_task (6,858,225,719 samples, 28.95%)tokio::runtime::scheduler::multi_thread::worker..tokio::runtime::coop::budget (6,852,278,699 samples, 28.93%)tokio::runtime::coop::budgettokio::runtime::coop::with_budget (6,852,278,699 samples, 28.93%)tokio::runtime::coop::with_budgettokio::runtime::scheduler::multi_thread::worker::Context::run_task::_{{closure}} (6,852,278,699 samples, 28.93%)tokio::runtime::scheduler::multi_thread::worker..tokio::runtime::task::LocalNotified<S>::run (6,831,615,710 samples, 28.84%)tokio::runtime::task::LocalNotified<S>::runtokio::runtime::task::raw::RawTask::poll (6,831,615,710 samples, 28.84%)tokio::runtime::task::raw::RawTask::polltokio::runtime::task::raw::poll (6,831,615,710 samples, 28.84%)tokio::runtime::task::raw::polltokio::runtime::task::harness::Harness<T,S>::poll (6,817,226,199 samples, 28.78%)tokio::runtime::task::harness::Harness<T,S>::p..tokio::runtime::task::harness::Harness<T,S>::poll_inner (6,817,226,199 samples, 28.78%)tokio::runtime::task::harness::Harness<T,S>::p..tokio::runtime::task::state::State::transition_to_idle (9,934,491 samples, 0.04%)tokio::runtime::task::state::State::fetch_update_action (9,934,491 samples, 0.04%)[libc.so.6] (12,523,753,545 samples, 52.87%)[libc.so.6]std::sys::pal::unix::thread::Thread::new::thread_start (12,463,106,312 samples, 52.62%)std::sys::pal::unix::thread::Thread::new::thread_start<alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once (12,463,106,312 samples, 52.62%)<alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once<alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once (12,463,106,312 samples, 52.62%)<alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_oncecore::ops::function::FnOnce::call_once{{vtable.shim}} (12,463,106,312 samples, 52.62%)core::ops::function::FnOnce::call_once{{vtable.shim}}std::thread::Builder::spawn_unchecked_::_{{closure}} (12,463,106,312 samples, 52.62%)std::thread::Builder::spawn_unchecked_::_{{closure}}std::panic::catch_unwind (12,463,106,312 samples, 52.62%)std::panic::catch_unwindstd::panicking::try (12,463,106,312 samples, 52.62%)std::panicking::trystd::panicking::try::do_call (12,463,106,312 samples, 52.62%)std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once (12,463,106,312 samples, 52.62%)<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::cal..std::thread::Builder::spawn_unchecked_::_{{closure}}::_{{closure}} (12,463,106,312 samples, 52.62%)std::thread::Builder::spawn_unchecked_::_{{closure}}::_{{closure}}std::sys::backtrace::__rust_begin_short_backtrace (12,463,106,312 samples, 52.62%)std::sys::backtrace::__rust_begin_short_backtracetokio::runtime::blocking::pool::Spawner::spawn_thread::_{{closure}} (12,463,106,312 samples, 52.62%)tokio::runtime::blocking::pool::Spawner::spawn_thread::_{{closure}}tokio::runtime::blocking::pool::Inner::run (12,463,106,312 samples, 52.62%)tokio::runtime::blocking::pool::Inner::runtokio::runtime::blocking::pool::Task::run (12,463,106,312 samples, 52.62%)tokio::runtime::blocking::pool::Task::runtokio::runtime::task::UnownedTask<S>::run (12,463,106,312 samples, 52.62%)tokio::runtime::task::UnownedTask<S>::runtokio::runtime::task::raw::RawTask::poll (12,463,106,312 samples, 52.62%)tokio::runtime::task::raw::RawTask::polltokio::runtime::task::raw::poll (12,463,106,312 samples, 52.62%)tokio::runtime::task::raw::polltokio::runtime::task::harness::Harness<T,S>::poll (12,463,106,312 samples, 52.62%)tokio::runtime::task::harness::Harness<T,S>::polltokio::runtime::task::harness::Harness<T,S>::poll_inner (12,463,106,312 samples, 52.62%)tokio::runtime::task::harness::Harness<T,S>::poll_innertokio::runtime::task::harness::poll_future (12,463,106,312 samples, 52.62%)tokio::runtime::task::harness::poll_futurestd::panic::catch_unwind (12,463,106,312 samples, 52.62%)std::panic::catch_unwindstd::panicking::try (12,463,106,312 samples, 52.62%)std::panicking::trystd::panicking::try::do_call (12,463,106,312 samples, 52.62%)std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once (12,463,106,312 samples, 52.62%)<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::cal..tokio::runtime::task::harness::poll_future::_{{closure}} (12,463,106,312 samples, 52.62%)tokio::runtime::task::harness::poll_future::_{{closure}}tokio::runtime::task::core::Core<T,S>::poll (12,463,106,312 samples, 52.62%)tokio::runtime::task::core::Core<T,S>::polltokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut (12,463,106,312 samples, 52.62%)tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_muttokio::runtime::task::core::Core<T,S>::poll::_{{closure}} (12,463,106,312 samples, 52.62%)tokio::runtime::task::core::Core<T,S>::poll::_{{closure}}<tokio::runtime::blocking::task::BlockingTask<T> as core::future::future::Future>::poll (12,463,106,312 samples, 52.62%)<tokio::runtime::blocking::task::BlockingTask<T> as core::future::future::Future>::polltokio::runtime::scheduler::multi_thread::worker::Launch::launch::_{{closure}} (12,463,106,312 samples, 52.62%)tokio::runtime::scheduler::multi_thread::worker::Launch::launch::_{{closure}}tokio::runtime::scheduler::multi_thread::worker::run (12,463,106,312 samples, 52.62%)tokio::runtime::scheduler::multi_thread::worker::runtokio::runtime::context::runtime::enter_runtime (12,463,106,312 samples, 52.62%)tokio::runtime::context::runtime::enter_runtimetokio::runtime::scheduler::multi_thread::worker::run::_{{closure}} (12,463,106,312 samples, 52.62%)tokio::runtime::scheduler::multi_thread::worker::run::_{{closure}}tokio::runtime::context::set_scheduler (12,463,106,312 samples, 52.62%)tokio::runtime::context::set_schedulerstd::thread::local::LocalKey<T>::with (12,463,106,312 samples, 52.62%)std::thread::local::LocalKey<T>::withstd::thread::local::LocalKey<T>::try_with (12,463,106,312 samples, 52.62%)std::thread::local::LocalKey<T>::try_withtokio::runtime::context::set_scheduler::_{{closure}} (12,463,106,312 samples, 52.62%)tokio::runtime::context::set_scheduler::_{{closure}}tokio::runtime::context::scoped::Scoped<T>::set (12,463,106,312 samples, 52.62%)tokio::runtime::context::scoped::Scoped<T>::settokio::runtime::scheduler::multi_thread::worker::run::_{{closure}}::_{{closure}} (12,463,106,312 samples, 52.62%)tokio::runtime::scheduler::multi_thread::worker::run::_{{closure}}::_{{closure}}tokio::runtime::scheduler::multi_thread::worker::Context::run (12,463,106,312 samples, 52.62%)tokio::runtime::scheduler::multi_thread::worker::Context::runtokio::runtime::scheduler::multi_thread::worker::Core::next_task (8,810,115 samples, 0.04%)tokio::runtime::scheduler::multi_thread::worker::Core::tune_global_queue_interval (8,810,115 samples, 0.04%)tokio::runtime::scheduler::multi_thread::stats::Stats::tuned_global_queue_interval (8,810,115 samples, 0.04%)core::cmp::Ord::clamp (4,770,317 samples, 0.02%)pgdog::backend::pool::connection::Connection::try_conn::_{{closure}} (3,682,273 samples, 0.02%)pgdog::backend::pool::cluster::Cluster::replica::_{{closure}} (3,682,273 samples, 0.02%)core::slice::<impl [T]>::get (3,682,273 samples, 0.02%)<usize as core::slice::index::SliceIndex<[T]>>::get (3,682,273 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::pool::connection::binding::Binding::send<pgdog::backend::protocol::protocol_message::ProtocolMessage>::{{closure}}> (13,998,159 samples, 0.06%)[libc.so.6] (12,932,652,090 samples, 54.60%)[libc.so.6]std::sys::pal::unix::thread::Thread::new::thread_start (67,436,111 samples, 0.28%)<alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once (67,436,111 samples, 0.28%)<alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once (67,436,111 samples, 0.28%)core::ops::function::FnOnce::call_once{{vtable.shim}} (67,436,111 samples, 0.28%)std::thread::Builder::spawn_unchecked_::_{{closure}} (67,436,111 samples, 0.28%)std::panic::catch_unwind (67,436,111 samples, 0.28%)std::panicking::try (67,436,111 samples, 0.28%)std::panicking::try::do_call (67,436,111 samples, 0.28%)<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once (67,436,111 samples, 0.28%)std::thread::Builder::spawn_unchecked_::_{{closure}}::_{{closure}} (67,436,111 samples, 0.28%)std::sys::backtrace::__rust_begin_short_backtrace (67,436,111 samples, 0.28%)tokio::runtime::blocking::pool::Spawner::spawn_thread::_{{closure}} (67,436,111 samples, 0.28%)tokio::runtime::blocking::pool::Inner::run (67,436,111 samples, 0.28%)tokio::runtime::blocking::pool::Task::run (67,436,111 samples, 0.28%)tokio::runtime::task::UnownedTask<S>::run (67,436,111 samples, 0.28%)tokio::runtime::task::raw::RawTask::poll (67,436,111 samples, 0.28%)tokio::runtime::task::raw::poll (67,436,111 samples, 0.28%)tokio::runtime::task::harness::Harness<T,S>::poll (67,436,111 samples, 0.28%)tokio::runtime::task::harness::Harness<T,S>::poll_inner (67,436,111 samples, 0.28%)tokio::runtime::task::harness::poll_future (67,436,111 samples, 0.28%)std::panic::catch_unwind (67,436,111 samples, 0.28%)std::panicking::try (67,436,111 samples, 0.28%)std::panicking::try::do_call (67,436,111 samples, 0.28%)<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once (67,436,111 samples, 0.28%)tokio::runtime::task::harness::poll_future::_{{closure}} (67,436,111 samples, 0.28%)tokio::runtime::task::core::Core<T,S>::poll (67,436,111 samples, 0.28%)tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut (67,436,111 samples, 0.28%)tokio::runtime::task::core::Core<T,S>::poll::_{{closure}} (67,436,111 samples, 0.28%)<tokio::runtime::blocking::task::BlockingTask<T> as core::future::future::Future>::poll (67,436,111 samples, 0.28%)tokio::runtime::scheduler::multi_thread::worker::Launch::launch::_{{closure}} (67,436,111 samples, 0.28%)tokio::runtime::scheduler::multi_thread::worker::run (67,436,111 samples, 0.28%)tokio::runtime::context::runtime::enter_runtime (67,436,111 samples, 0.28%)tokio::runtime::scheduler::multi_thread::worker::run::_{{closure}} (67,436,111 samples, 0.28%)tokio::runtime::context::set_scheduler (67,436,111 samples, 0.28%)std::thread::local::LocalKey<T>::with (67,436,111 samples, 0.28%)std::thread::local::LocalKey<T>::try_with (67,436,111 samples, 0.28%)tokio::runtime::context::set_scheduler::_{{closure}} (67,436,111 samples, 0.28%)tokio::runtime::context::scoped::Scoped<T>::set (67,436,111 samples, 0.28%)tokio::runtime::scheduler::multi_thread::worker::run::_{{closure}}::_{{closure}} (67,436,111 samples, 0.28%)tokio::runtime::scheduler::multi_thread::worker::Context::run (67,436,111 samples, 0.28%)tokio::runtime::scheduler::multi_thread::worker::Context::run_task (67,436,111 samples, 0.28%)tokio::runtime::coop::budget (67,436,111 samples, 0.28%)tokio::runtime::coop::with_budget (67,436,111 samples, 0.28%)tokio::runtime::scheduler::multi_thread::worker::Context::run_task::_{{closure}} (67,436,111 samples, 0.28%)tokio::runtime::task::LocalNotified<S>::run (67,436,111 samples, 0.28%)tokio::runtime::task::raw::RawTask::poll (67,436,111 samples, 0.28%)tokio::runtime::task::raw::poll (67,436,111 samples, 0.28%)tokio::runtime::task::harness::Harness<T,S>::poll (67,436,111 samples, 0.28%)tokio::runtime::task::harness::Harness<T,S>::poll_inner (67,436,111 samples, 0.28%)tokio::runtime::task::harness::poll_future (67,436,111 samples, 0.28%)std::panic::catch_unwind (67,436,111 samples, 0.28%)std::panicking::try (67,436,111 samples, 0.28%)std::panicking::try::do_call (67,436,111 samples, 0.28%)<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once (67,436,111 samples, 0.28%)tokio::runtime::task::harness::poll_future::_{{closure}} (67,436,111 samples, 0.28%)tokio::runtime::task::core::Core<T,S>::poll (67,436,111 samples, 0.28%)tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut (67,436,111 samples, 0.28%)tokio::runtime::task::core::Core<T,S>::poll::_{{closure}} (67,436,111 samples, 0.28%)<tokio_util::task::task_tracker::TrackedFuture<F> as core::future::future::Future>::poll (67,436,111 samples, 0.28%)pgdog::frontend::listener::Listener::listen::_{{closure}}::_{{closure}} (67,436,111 samples, 0.28%)pgdog::frontend::listener::Listener::handle_client::_{{closure}} (67,436,111 samples, 0.28%)pgdog::frontend::client::Client::spawn::_{{closure}} (67,436,111 samples, 0.28%)pgdog::frontend::client::Client::spawn_internal::_{{closure}} (67,436,111 samples, 0.28%)pgdog::frontend::client::Client::run::_{{closure}} (67,436,111 samples, 0.28%)pgdog::frontend::client::Client::client_messages::_{{closure}} (67,436,111 samples, 0.28%)pgdog::backend::pool::connection::Connection::send::_{{closure}} (67,436,111 samples, 0.28%)pgdog::backend::pool::connection::binding::Binding::send::_{{closure}} (38,970,471 samples, 0.16%)<core::hash::sip::Hasher<S> as core::hash::Hasher>::write (4,308,726 samples, 0.02%)core::hash::sip::u8to64_le (4,308,726 samples, 0.02%)<pgdog::net::stream::Stream as tokio::io::async_read::AsyncRead>::poll_read (5,989,713 samples, 0.03%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (5,989,713 samples, 0.03%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_read::AsyncRead>::poll_read (5,989,713 samples, 0.03%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_buf_read::AsyncBufRead>::poll_fill_buf (5,989,713 samples, 0.03%)<tokio::net::tcp::stream::TcpStream as tokio::io::async_read::AsyncRead>::poll_read (10,054,576 samples, 0.04%)tokio::net::tcp::stream::TcpStream::poll_read_priv (10,054,576 samples, 0.04%)tokio::io::poll_evented::PollEvented<E>::poll_read (10,054,576 samples, 0.04%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read (10,054,576 samples, 0.04%)mio::io_source::IoSource<T>::do_io (10,054,576 samples, 0.04%)mio::sys::unix::selector::stateless_io_source::IoSourceState::do_io (10,054,576 samples, 0.04%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read::_{{closure}} (10,054,576 samples, 0.04%)<&std::net::tcp::TcpStream as std::io::Read>::read (10,054,576 samples, 0.04%)std::sys::net::connection::socket::TcpStream::read (10,054,576 samples, 0.04%)std::sys::net::connection::socket::unix::Socket::read (10,054,576 samples, 0.04%)std::sys::net::connection::socket::unix::Socket::recv_with_flags (10,054,576 samples, 0.04%)std::sys::pal::unix::cvt (10,054,576 samples, 0.04%)<isize as std::sys::pal::unix::IsMinusOne>::is_minus_one (10,054,576 samples, 0.04%)<tokio::time::timeout::Timeout<T> as core::future::future::Future>::poll (4,359,433 samples, 0.02%)[libc.so.6] (8,558,717 samples, 0.04%)<tokio::runtime::time::entry::TimerEntry as core::ops::drop::Drop>::drop (5,592,371 samples, 0.02%)tokio::runtime::time::entry::TimerEntry::cancel (5,592,371 samples, 0.02%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::clear_entry (5,592,371 samples, 0.02%)tokio::runtime::time::entry::TimerHandle::fire (5,592,371 samples, 0.02%)tokio::runtime::time::entry::StateCell::fire (5,592,371 samples, 0.02%)tokio::sync::task::atomic_waker::AtomicWaker::take_waker (5,592,371 samples, 0.02%)core::sync::atomic::AtomicUsize::fetch_or (5,592,371 samples, 0.02%)core::sync::atomic::atomic_or (5,592,371 samples, 0.02%)[unknown] (9,338,254 samples, 0.04%)bytes::bytes::shared_drop (3,745,883 samples, 0.02%)<core::sync::atomic::AtomicPtr<T> as bytes::loom::sync::atomic::AtomicMut<T>>::with_mut (3,745,883 samples, 0.02%)bytes::bytes::shared_drop::_{{closure}} (3,745,883 samples, 0.02%)_rjem_je_extent_record (6,686,724 samples, 0.03%)extent_deactivate_locked (6,686,724 samples, 0.03%)extent_deactivate_locked_impl (6,686,724 samples, 0.03%)<tokio::time::timeout::Timeout<T> as core::future::future::Future>::poll (6,686,724 samples, 0.03%)pgdog::backend::pool::connection::Connection::read::_{{closure}} (6,686,724 samples, 0.03%)_rjem_sdallocx (2,493,496 samples, 0.01%)free_fastpath (2,493,496 samples, 0.01%)core::ptr::drop_in_place<(tokio::sync::notify::Notified,tokio::time::timeout::Timeout<pgdog::backend::pool::connection::Connection::read::{{closure}}>,pgdog::frontend::client::Client::buffer::{{closure}})> (4,044,962 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::error::Error> (6,225,378 samples, 0.03%)core::ptr::drop_in_place<pgdog::backend::pool::pool_impl::Pool::get_internal::{{closure}}> (4,948,674 samples, 0.02%)pgdog::backend::pool::connection::Connection::try_conn::_{{closure}} (3,361,505 samples, 0.01%)pgdog::backend::pool::cluster::Cluster::replica::_{{closure}} (3,361,505 samples, 0.01%)<tokio::time::timeout::Timeout<T> as core::future::future::Future>::poll (4,364,685 samples, 0.02%)pgdog::backend::pool::replicas::Replicas::get_internal::_{{closure}} (4,364,685 samples, 0.02%)core::iter::traits::iterator::Iterator::collect (4,364,685 samples, 0.02%)<alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter (4,364,685 samples, 0.02%)<alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter (4,364,685 samples, 0.02%)<alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter (4,364,685 samples, 0.02%)alloc::vec::Vec<T>::with_capacity (4,364,685 samples, 0.02%)alloc::vec::Vec<T,A>::with_capacity_in (4,364,685 samples, 0.02%)alloc::raw_vec::RawVec<T,A>::with_capacity_in (4,364,685 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::with_capacity_in (4,364,685 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::try_allocate_in (4,364,685 samples, 0.02%)pgdog::backend::pool::shard::Shard::replica::_{{closure}} (6,638,903 samples, 0.03%)pgdog::backend::pool::replicas::Replicas::get::_{{closure}} (6,638,903 samples, 0.03%)pgdog::frontend::client::Client::run::_{{closure}} (2,554,020 samples, 0.01%)pgdog::frontend::client::Client::server_message::_{{closure}} (2,554,020 samples, 0.01%)<tokio::io::util::read_int::ReadI32<R> as core::future::future::Future>::poll (3,384,318 samples, 0.01%)<tokio::io::util::read_int::ReadU8<R> as core::future::future::Future>::poll (5,665,063 samples, 0.02%)tokio::io::read_buf::ReadBuf::new (5,665,063 samples, 0.02%)bytes::bytes_mut::BytesMut::freeze (3,300,345 samples, 0.01%)bytes::bytes_mut::BytesMut::get_vec_pos (3,300,345 samples, 0.01%)pgdog::net::stream::Stream::read::_{{closure}} (16,579,796 samples, 0.07%)bytes::bytes_mut::BytesMut::with_capacity (4,230,070 samples, 0.02%)bytes::bytes_mut::BytesMut::from_vec (4,230,070 samples, 0.02%)bytes::bytes_mut::original_capacity_to_repr (4,230,070 samples, 0.02%)core::cmp::min (4,230,070 samples, 0.02%)core::cmp::Ord::min (4,230,070 samples, 0.02%)std::sys::pal::unix::time::Timespec::sub_timespec (4,569,898 samples, 0.02%)tokio::runtime::io::driver::Driver::turn (4,621,940 samples, 0.02%)tokio::runtime::io::registration::Registration::poll_ready (5,954,662 samples, 0.03%)[pgdog] (114,236,672 samples, 0.48%)tokio::runtime::scheduler::multi_thread::worker::<impl tokio::runtime::scheduler::multi_thread::handle::Handle>::schedule_task (2,947,295 samples, 0.01%)<arc_swap::strategy::hybrid::HybridStrategy<Cfg> as arc_swap::strategy::sealed::InnerStrategy<T>>::load::_{{closure}} (5,006,861 samples, 0.02%)arc_swap::strategy::hybrid::HybridProtection<T>::attempt (5,006,861 samples, 0.02%)alloc::vec::Vec<T>::with_capacity (3,293,326 samples, 0.01%)alloc::vec::Vec<T,A>::with_capacity_in (3,293,326 samples, 0.01%)alloc::raw_vec::RawVec<T,A>::with_capacity_in (3,293,326 samples, 0.01%)alloc::raw_vec::RawVecInner<A>::with_capacity_in (3,293,326 samples, 0.01%)alloc::raw_vec::RawVecInner<A>::try_allocate_in (3,293,326 samples, 0.01%)<alloc::alloc::Global as core::alloc::Allocator>::allocate (3,293,326 samples, 0.01%)alloc::alloc::Global::alloc_impl (3,293,326 samples, 0.01%)alloc::alloc::alloc (3,293,326 samples, 0.01%)__rust_alloc (3,293,326 samples, 0.01%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::alloc (3,293,326 samples, 0.01%)alloc::vec::Vec<T,A>::push (6,499,665 samples, 0.03%)core::ptr::write (6,499,665 samples, 0.03%)<pgdog::net::messages::bind::Bind as pgdog::net::messages::FromBytes>::from_bytes (22,190,845 samples, 0.09%)core::iter::traits::iterator::Iterator::collect (14,668,990 samples, 0.06%)<alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter (14,668,990 samples, 0.06%)<alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter (14,668,990 samples, 0.06%)<alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter (14,668,990 samples, 0.06%)<alloc::vec::Vec<T,A> as alloc::vec::spec_extend::SpecExtend<T,I>>::spec_extend (14,668,990 samples, 0.06%)alloc::vec::Vec<T,A>::extend_trusted (14,668,990 samples, 0.06%)core::iter::traits::iterator::Iterator::for_each (14,668,990 samples, 0.06%)<core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::fold (14,668,990 samples, 0.06%)core::iter::traits::iterator::Iterator::fold (14,668,990 samples, 0.06%)core::iter::adapters::map::map_fold::_{{closure}} (14,668,990 samples, 0.06%)<pgdog::net::messages::bind::Bind as pgdog::net::messages::FromBytes>::from_bytes::_{{closure}} (14,668,990 samples, 0.06%)core::iter::traits::iterator::Iterator::for_each (11,375,664 samples, 0.05%)core::iter::traits::iterator::Iterator::fold (11,375,664 samples, 0.05%)core::iter::traits::iterator::Iterator::for_each::call::_{{closure}} (11,375,664 samples, 0.05%)<pgdog::net::messages::bind::Bind as pgdog::net::messages::FromBytes>::from_bytes::_{{closure}}::_{{closure}} (11,375,664 samples, 0.05%)bytes::buf::buf_impl::Buf::get_u8 (4,875,999 samples, 0.02%)<pgdog::net::messages::command_complete::CommandComplete as pgdog::net::messages::FromBytes>::from_bytes (2,412,693 samples, 0.01%)<pgdog::net::messages::parse::Parse as core::clone::Clone>::clone (6,050,096 samples, 0.03%)<alloc::sync::Arc<T,A> as core::clone::Clone>::clone (6,050,096 samples, 0.03%)alloc::sync::Arc<T,A>::inner (6,050,096 samples, 0.03%)core::ptr::non_null::NonNull<T>::as_ref (6,050,096 samples, 0.03%)<pgdog::net::messages::parse::Parse as pgdog::net::messages::FromBytes>::from_bytes (5,292,414 samples, 0.02%)bytes::buf::buf_impl::Buf::get_i16 (5,292,414 samples, 0.02%)<&mut T as bytes::buf::buf_impl::Buf>::remaining (5,292,414 samples, 0.02%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_buf_read::AsyncBufRead>::consume (12,225,332 samples, 0.05%)core::slice::index::<impl core::ops::index::Index<I> for [T]>::index (5,704,658 samples, 0.02%)<core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::index (5,704,658 samples, 0.02%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (28,640,009 samples, 0.12%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_read::AsyncRead>::poll_read (28,640,009 samples, 0.12%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_buf_read::AsyncBufRead>::poll_fill_buf (16,414,677 samples, 0.07%)tokio::io::read_buf::ReadBuf::filled (6,092,458 samples, 0.03%)<pgdog::net::stream::Stream as tokio::io::async_read::AsyncRead>::poll_read (42,369,786 samples, 0.18%)pgdog::net::stream::_::<impl pgdog::net::stream::Stream>::project (5,338,272 samples, 0.02%)<tokio::io::util::write_all::WriteAll<W> as core::future::future::Future>::poll (5,761,078 samples, 0.02%)<&mut T as tokio::io::async_write::AsyncWrite>::poll_write (5,761,078 samples, 0.02%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_write::AsyncWrite>::poll_write (5,761,078 samples, 0.02%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_write::AsyncWrite>::poll_write (5,761,078 samples, 0.02%)<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_write::AsyncWrite>::poll_write (5,761,078 samples, 0.02%)<tokio::runtime::time::entry::TimerEntry as core::ops::drop::Drop>::drop (5,772,650 samples, 0.02%)tokio::runtime::time::entry::TimerEntry::cancel (5,772,650 samples, 0.02%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::clear_entry (5,772,650 samples, 0.02%)tokio::loom::std::parking_lot::RwLock<T>::read (5,772,650 samples, 0.02%)lock_api::rwlock::RwLock<R,T>::read (5,772,650 samples, 0.02%)<parking_lot::raw_rwlock::RawRwLock as lock_api::rwlock::RawRwLock>::lock_shared (5,772,650 samples, 0.02%)parking_lot::raw_rwlock::RawRwLock::try_lock_shared_fast (5,772,650 samples, 0.02%)core::sync::atomic::AtomicUsize::compare_exchange_weak (5,772,650 samples, 0.02%)core::sync::atomic::atomic_compare_exchange_weak (5,772,650 samples, 0.02%)<tokio::sync::notify::Notified as core::ops::drop::Drop>::drop (3,610,943 samples, 0.02%)<tokio::time::timeout::Timeout<T> as core::future::future::Future>::poll (42,323,219 samples, 0.18%)pgdog::backend::pool::connection::Connection::read::_{{closure}} (32,921,774 samples, 0.14%)pgdog::backend::pool::connection::binding::Binding::read::_{{closure}} (26,498,898 samples, 0.11%)[libc.so.6] (46,104,658 samples, 0.19%)[pgdog] (3,498,296 samples, 0.01%)pgdog::backend::pool::connection::Connection::connect::_{{closure}} (3,498,296 samples, 0.01%)pgdog::backend::server::Server::send::_{{closure}} (5,002,278 samples, 0.02%)<alloc::vec::into_iter::IntoIter<T,A> as core::iter::traits::iterator::Iterator>::next (5,002,278 samples, 0.02%)core::ptr::non_null::NonNull<T>::add (5,002,278 samples, 0.02%)tokio::runtime::io::registration::Registration::poll_ready (3,741,672 samples, 0.02%)tokio::runtime::io::scheduled_io::ScheduledIo::poll_readiness (3,741,672 samples, 0.02%)<core::task::wake::Waker as core::clone::Clone>::clone (3,741,672 samples, 0.02%)[unknown] (12,291,843 samples, 0.05%)tokio::runtime::task::raw::poll (3,547,893 samples, 0.01%)tokio::runtime::task::harness::Harness<T,S>::poll (3,547,893 samples, 0.01%)tokio::runtime::task::harness::Harness<T,S>::poll_inner (3,547,893 samples, 0.01%)tokio::runtime::task::harness::poll_future (3,547,893 samples, 0.01%)std::panic::catch_unwind (3,547,893 samples, 0.01%)std::panicking::try (3,547,893 samples, 0.01%)std::panicking::try::do_call (3,547,893 samples, 0.01%)<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once (3,547,893 samples, 0.01%)tokio::runtime::task::harness::poll_future::_{{closure}} (3,547,893 samples, 0.01%)tokio::runtime::task::core::Core<T,S>::poll (3,547,893 samples, 0.01%)tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut (3,547,893 samples, 0.01%)tokio::runtime::task::core::Core<T,S>::poll::_{{closure}} (3,547,893 samples, 0.01%)<tokio::runtime::blocking::task::BlockingTask<T> as core::future::future::Future>::poll (3,547,893 samples, 0.01%)tokio::runtime::scheduler::multi_thread::worker::Launch::launch::_{{closure}} (3,547,893 samples, 0.01%)tokio::runtime::scheduler::multi_thread::worker::run (3,547,893 samples, 0.01%)tokio::runtime::context::runtime::enter_runtime (3,547,893 samples, 0.01%)tokio::runtime::scheduler::multi_thread::worker::run::_{{closure}} (3,547,893 samples, 0.01%)tokio::runtime::context::set_scheduler (3,547,893 samples, 0.01%)std::thread::local::LocalKey<T>::with (3,547,893 samples, 0.01%)std::thread::local::LocalKey<T>::try_with (3,547,893 samples, 0.01%)tokio::runtime::context::set_scheduler::_{{closure}} (3,547,893 samples, 0.01%)tokio::runtime::context::scoped::Scoped<T>::set (3,547,893 samples, 0.01%)tokio::runtime::scheduler::multi_thread::worker::run::_{{closure}}::_{{closure}} (3,547,893 samples, 0.01%)tokio::runtime::scheduler::multi_thread::worker::Context::run (3,547,893 samples, 0.01%)tokio::runtime::scheduler::multi_thread::worker::Context::park (3,547,893 samples, 0.01%)cache_bin_alloc_easy (5,693,365 samples, 0.02%)cache_bin_alloc_impl (5,693,365 samples, 0.02%)_rjem_malloc (10,178,954 samples, 0.04%)imalloc_fastpath (10,178,954 samples, 0.04%)sz_size2index_usize_fastpath (4,485,589 samples, 0.02%)sz_size2index_lookup_impl (4,485,589 samples, 0.02%)alloc::vec::Vec<T,A>::as_mut_ptr (5,374,567 samples, 0.02%)alloc::raw_vec::RawVec<T,A>::ptr (5,374,567 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::ptr (5,374,567 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::non_null (5,374,567 samples, 0.02%)alloc::string::String::push (39,744,639 samples, 0.17%)alloc::vec::Vec<T,A>::push (33,638,907 samples, 0.14%)core::ptr::write (3,108,441 samples, 0.01%)bytes::bytes::promotable_even_drop (4,408,692 samples, 0.02%)<core::sync::atomic::AtomicPtr<T> as bytes::loom::sync::atomic::AtomicMut<T>>::with_mut (4,408,692 samples, 0.02%)bytes::bytes::promotable_even_drop::_{{closure}} (4,408,692 samples, 0.02%)bytes::bytes::release_shared (4,408,692 samples, 0.02%)core::sync::atomic::AtomicUsize::load (4,408,692 samples, 0.02%)core::sync::atomic::atomic_load (4,408,692 samples, 0.02%)bytes::bytes::shallow_clone_vec (5,329,457 samples, 0.02%)bytes::bytes::shared_drop (10,071,319 samples, 0.04%)<core::sync::atomic::AtomicPtr<T> as bytes::loom::sync::atomic::AtomicMut<T>>::with_mut (5,500,897 samples, 0.02%)bytes::bytes::shared_drop::_{{closure}} (5,500,897 samples, 0.02%)clock_gettime (3,145,111 samples, 0.01%)core::ptr::drop_in_place<(tokio::sync::notify::Notified,tokio::time::timeout::Timeout<pgdog::backend::pool::connection::Connection::read::{{closure}}>,pgdog::frontend::client::Client::buffer::{{closure}})> (14,264,591 samples, 0.06%)core::ptr::drop_in_place<tokio::time::timeout::Timeout<pgdog::backend::pool::connection::Connection::read::{{closure}}>> (8,550,592 samples, 0.04%)core::ptr::drop_in_place<pgdog::backend::pool::connection::Connection::read::{{closure}}> (3,879,875 samples, 0.02%)core::ptr::drop_in_place<alloc::vec::Vec<pgdog::backend::protocol::protocol_message::ProtocolMessage>> (4,725,079 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::pool::connection::binding::Binding::read::{{closure}}> (4,994,710 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::server::Server::link_client::{{closure}}> (3,655,892 samples, 0.02%)core::ptr::drop_in_place<pgdog::frontend::router::parser::route::Route> (4,947,965 samples, 0.02%)core::ptr::drop_in_place<alloc::vec::Vec<pgdog::frontend::router::parser::order_by::OrderBy>> (4,947,965 samples, 0.02%)hashbrown::map::HashMap<K,V,S,A>::remove (5,489,602 samples, 0.02%)hashbrown::map::HashMap<K,V,S,A>::remove_entry (5,489,602 samples, 0.02%)hashbrown::raw::RawTable<T,A>::remove_entry (5,489,602 samples, 0.02%)hashbrown::raw::RawTable<T,A>::remove (5,489,602 samples, 0.02%)hashbrown::raw::RawTable<T,A>::erase_no_drop (5,489,602 samples, 0.02%)hashbrown::raw::RawTableInner::erase (5,489,602 samples, 0.02%)pgdog::backend::pool::connection::Connection::connect::_{{closure}} (3,513,131 samples, 0.01%)pgdog::backend::pool::connection::Connection::try_conn::_{{closure}} (10,219,248 samples, 0.04%)pgdog::backend::pool::healthcheck::Healtcheck::healthcheck::_{{closure}} (3,366,063 samples, 0.01%)pgdog::backend::pool::inner::Inner::put (5,070,252 samples, 0.02%)alloc::collections::vec_deque::VecDeque<T,A>::push_back (5,070,252 samples, 0.02%)pgdog::backend::pool::inner::Inner::maybe_check_in (7,223,851 samples, 0.03%)core::iter::traits::iterator::Iterator::collect (4,570,958 samples, 0.02%)<alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter (4,570,958 samples, 0.02%)<alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter (4,570,958 samples, 0.02%)<alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter (4,570,958 samples, 0.02%)alloc::vec::Vec<T>::with_capacity (4,570,958 samples, 0.02%)alloc::vec::Vec<T,A>::with_capacity_in (4,570,958 samples, 0.02%)alloc::raw_vec::RawVec<T,A>::with_capacity_in (4,570,958 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::with_capacity_in (4,570,958 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::try_allocate_in (4,570,958 samples, 0.02%)<alloc::alloc::Global as core::alloc::Allocator>::allocate (4,570,958 samples, 0.02%)alloc::alloc::Global::alloc_impl (4,570,958 samples, 0.02%)alloc::alloc::alloc (4,570,958 samples, 0.02%)__rust_alloc (4,570,958 samples, 0.02%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::alloc (4,570,958 samples, 0.02%)<tokio::time::timeout::Timeout<T> as core::future::future::Future>::poll (10,808,637 samples, 0.05%)pgdog::backend::pool::replicas::Replicas::get_internal::_{{closure}} (10,808,637 samples, 0.05%)core::ptr::drop_in_place<rand::rngs::thread::ThreadRng> (6,237,679 samples, 0.03%)core::ptr::drop_in_place<alloc::rc::Rc<core::cell::UnsafeCell<rand::rngs::adapter::reseeding::ReseedingRng<rand_chacha::chacha::ChaCha12Core,rand_core::os::OsRng>>>> (6,237,679 samples, 0.03%)<alloc::rc::Rc<T,A> as core::ops::drop::Drop>::drop (6,237,679 samples, 0.03%)pgdog::backend::pool::shard::Shard::replica::_{{closure}} (19,372,020 samples, 0.08%)pgdog::backend::pool::replicas::Replicas::get::_{{closure}} (16,057,938 samples, 0.07%)tokio::time::timeout::timeout (5,249,301 samples, 0.02%)pgdog::backend::server::Server::flush::_{{closure}} (3,949,661 samples, 0.02%)pgdog::backend::server::Server::link_client::_{{closure}} (3,934,177 samples, 0.02%)pgdog::net::parameter::Parameters::merge (3,934,177 samples, 0.02%)<once_cell::sync::Lazy<T,F> as core::ops::deref::Deref>::deref (3,934,177 samples, 0.02%)once_cell::sync::Lazy<T,F>::force (3,934,177 samples, 0.02%)once_cell::sync::OnceCell<T>::get_or_init (3,934,177 samples, 0.02%)once_cell::sync::OnceCell<T>::get_or_try_init (3,934,177 samples, 0.02%)once_cell::sync::OnceCell<T>::get (3,934,177 samples, 0.02%)once_cell::imp::OnceCell<T>::is_initialized (3,934,177 samples, 0.02%)pgdog::backend::protocol::state::ProtocolState::get_simulated (3,859,763 samples, 0.02%)alloc::collections::vec_deque::VecDeque<T,A>::front (3,859,763 samples, 0.02%)alloc::collections::vec_deque::VecDeque<T,A>::get (3,859,763 samples, 0.02%)pgdog::backend::server::Server::read::_{{closure}} (27,060,680 samples, 0.11%)tracing_core::metadata::LevelFilter::current (3,283,736 samples, 0.01%)core::sync::atomic::AtomicUsize::load (3,283,736 samples, 0.01%)core::sync::atomic::atomic_load (3,283,736 samples, 0.01%)pgdog::config::config (2,378,715 samples, 0.01%)arc_swap::ArcSwapAny<T,S>::load (2,378,715 samples, 0.01%)<arc_swap::strategy::hybrid::HybridStrategy<Cfg> as arc_swap::strategy::sealed::InnerStrategy<T>>::load (2,378,715 samples, 0.01%)arc_swap::debt::list::LocalNode::with (2,378,715 samples, 0.01%)std::thread::local::LocalKey<T>::try_with (2,378,715 samples, 0.01%)arc_swap::debt::list::LocalNode::with::_{{closure}} (2,378,715 samples, 0.01%)pgdog::frontend::buffer::Buffer::len (6,689,212 samples, 0.03%)core::iter::traits::iterator::Iterator::sum (6,689,212 samples, 0.03%)<usize as core::iter::traits::accum::Sum>::sum (6,689,212 samples, 0.03%)<core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::fold (6,689,212 samples, 0.03%)<core::slice::iter::Iter<T> as core::iter::traits::iterator::Iterator>::fold (6,689,212 samples, 0.03%)core::iter::adapters::map::map_fold::_{{closure}} (6,689,212 samples, 0.03%)pgdog::frontend::buffer::Buffer::len::_{{closure}} (6,689,212 samples, 0.03%)pgdog::backend::protocol::protocol_message::ProtocolMessage::len (6,689,212 samples, 0.03%)pgdog::net::messages::parse::Parse::len (3,216,958 samples, 0.01%)<alloc::sync::Arc<T,A> as core::ops::deref::Deref>::deref (3,216,958 samples, 0.01%)alloc::sync::Arc<T,A>::inner (3,216,958 samples, 0.01%)core::ptr::non_null::NonNull<T>::as_ref (3,216,958 samples, 0.01%)pgdog::frontend::buffer::Buffer::is_async (5,511,199 samples, 0.02%)core::slice::<impl [T]>::last (5,511,199 samples, 0.02%)<core::result::Result<T,E> as core::ops::try_trait::Try>::branch (7,924,756 samples, 0.03%)pgdog::frontend::client::inner::Inner::command (12,623,444 samples, 0.05%)core::option::Option<T>::map (12,623,444 samples, 0.05%)pgdog::frontend::client::inner::Inner::command::_{{closure}} (12,623,444 samples, 0.05%)pgdog::frontend::router::Router::query (12,623,444 samples, 0.05%)pgdog::frontend::router::parser::query::QueryParser::parse (12,623,444 samples, 0.05%)pgdog::frontend::buffer::Buffer::query (4,698,688 samples, 0.02%)pgdog::frontend::client::Client::client_messages::_{{closure}} (26,326,059 samples, 0.11%)pgdog::frontend::client::inner::Inner::connect::_{{closure}} (4,725,253 samples, 0.02%)pgdog::frontend::stats::Stats::connected (4,725,253 samples, 0.02%)std::time::Instant::duration_since (4,725,253 samples, 0.02%)std::time::Instant::checked_duration_since (4,725,253 samples, 0.02%)std::sys::pal::unix::time::Instant::checked_sub_instant (4,725,253 samples, 0.02%)entry_SYSCALL_64 (3,215,948 samples, 0.01%)<pgdog::net::messages::sync::Sync as pgdog::net::messages::FromBytes>::from_bytes (3,009,487 samples, 0.01%)bytes::buf::buf_impl::Buf::get_u8 (3,009,487 samples, 0.01%)<bytes::bytes::Bytes as bytes::buf::buf_impl::Buf>::advance (3,009,487 samples, 0.01%)bytes::bytes::Bytes::inc_start (3,009,487 samples, 0.01%)core::ptr::const_ptr::<impl *const T>::add (3,009,487 samples, 0.01%)<pgdog::backend::protocol::protocol_message::ProtocolMessage as pgdog::net::messages::FromBytes>::from_bytes (15,468,604 samples, 0.07%)bytes::buf::buf_impl::Buf::get_u8 (2,668,392 samples, 0.01%)core::ptr::drop_in_place<pgdog::net::messages::Message> (12,721,992 samples, 0.05%)core::ptr::drop_in_place<bytes::bytes::Bytes> (12,721,992 samples, 0.05%)<bytes::bytes::Bytes as core::ops::drop::Drop>::drop (12,721,992 samples, 0.05%)<core::future::poll_fn::PollFn<F> as core::future::future::Future>::poll (58,332,168 samples, 0.25%)pgdog::frontend::client::Client::run::_{{closure}}::_{{closure}} (58,332,168 samples, 0.25%)pgdog::frontend::client::Client::buffer::_{{closure}} (45,971,076 samples, 0.19%)tracing_core::metadata::LevelFilter::current (4,505,593 samples, 0.02%)core::sync::atomic::AtomicUsize::load (4,505,593 samples, 0.02%)core::sync::atomic::atomic_load (4,505,593 samples, 0.02%)entry_SYSCALL_64 (6,414,426 samples, 0.03%)core::ptr::drop_in_place<pgdog::frontend::client::inner::InnerBorrow> (4,397,181 samples, 0.02%)core::ptr::drop_in_place<pgdog::net::stream::Stream::send<pgdog::net::messages::Message>::{{closure}}> (6,537,545 samples, 0.03%)entry_SYSCALL_64 (6,537,545 samples, 0.03%)pgdog::frontend::client::Client::server_message::_{{closure}} (32,752,739 samples, 0.14%)pgdog::frontend::client::inner::Inner::transaction_mode (6,138,851 samples, 0.03%)pgdog::backend::pool::connection::Connection::transaction_mode (6,138,851 samples, 0.03%)pgdog::backend::pool::connection::Connection::cluster (6,138,851 samples, 0.03%)pgdog::frontend::client::Client::run::_{{closure}} (103,837,838 samples, 0.44%)tokio::time::timeout::timeout (4,032,501 samples, 0.02%)hashbrown::map::make_hash (3,187,264 samples, 0.01%)core::hash::BuildHasher::hash_one (3,187,264 samples, 0.01%)core::hash::impls::<impl core::hash::Hash for &T>::hash (3,187,264 samples, 0.01%)<pgdog::net::messages::backend_key::BackendKeyData as core::hash::Hash>::hash (3,187,264 samples, 0.01%)core::hash::impls::<impl core::hash::Hash for i32>::hash (3,187,264 samples, 0.01%)core::hash::Hasher::write_i32 (3,187,264 samples, 0.01%)core::hash::Hasher::write_u32 (3,187,264 samples, 0.01%)<fnv::FnvHasher as core::hash::Hasher>::write (3,187,264 samples, 0.01%)pgdog::frontend::comms::Comms::stats (14,228,958 samples, 0.06%)std::collections::hash::map::HashMap<K,V,S>::get_mut (14,228,958 samples, 0.06%)hashbrown::map::HashMap<K,V,S,A>::get_mut (14,228,958 samples, 0.06%)hashbrown::map::HashMap<K,V,S,A>::get_inner_mut (8,820,495 samples, 0.04%)hashbrown::raw::RawTable<T,A>::get_mut (5,633,231 samples, 0.02%)hashbrown::raw::RawTable<T,A>::find (5,633,231 samples, 0.02%)hashbrown::raw::RawTableInner::find_inner (5,633,231 samples, 0.02%)<hashbrown::control::bitmask::BitMaskIter as core::iter::traits::iterator::Iterator>::next (5,633,231 samples, 0.02%)hashbrown::control::bitmask::BitMask::lowest_set_bit (5,633,231 samples, 0.02%)hashbrown::control::bitmask::BitMask::nonzero_trailing_zeros (5,633,231 samples, 0.02%)core::num::nonzero::NonZero<u16>::trailing_zeros (5,633,231 samples, 0.02%)alloc::sync::Arc<T,A>::inner (4,862,484 samples, 0.02%)core::ptr::non_null::NonNull<T>::as_ref (4,862,484 samples, 0.02%)pgdog::frontend::router::parser::query::QueryParser::query (17,487,745 samples, 0.07%)core::ptr::drop_in_place<pgdog::backend::pool::cluster::ShardingSchema> (17,487,745 samples, 0.07%)core::ptr::drop_in_place<pgdog::backend::replication::sharded_tables::ShardedTables> (17,487,745 samples, 0.07%)core::ptr::drop_in_place<alloc::sync::Arc<alloc::vec::Vec<pgdog::config::ShardedTable>>> (17,487,745 samples, 0.07%)<alloc::sync::Arc<T,A> as core::ops::drop::Drop>::drop (17,487,745 samples, 0.07%)core::sync::atomic::AtomicUsize::fetch_sub (8,715,473 samples, 0.04%)core::sync::atomic::atomic_sub (8,715,473 samples, 0.04%)<tokio::io::util::read_exact::ReadExact<A> as core::future::future::Future>::poll (3,979,556 samples, 0.02%)<tokio::io::util::read_int::ReadI32<R> as core::future::future::Future>::poll (7,711,351 samples, 0.03%)tokio::io::read_buf::ReadBuf::filled (5,575,120 samples, 0.02%)<tokio::io::util::read_int::ReadU8<R> as core::future::future::Future>::poll (7,939,269 samples, 0.03%)tokio::io::read_buf::ReadBuf::new (4,778,794 samples, 0.02%)alloc::vec::Vec<T>::with_capacity (4,731,608 samples, 0.02%)alloc::vec::Vec<T,A>::with_capacity_in (4,731,608 samples, 0.02%)alloc::raw_vec::RawVec<T,A>::with_capacity_in (4,731,608 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::with_capacity_in (4,731,608 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::try_allocate_in (4,731,608 samples, 0.02%)pgdog::net::stream::Stream::read::_{{closure}} (41,234,806 samples, 0.17%)bytes::bytes_mut::BytesMut::with_capacity (16,713,599 samples, 0.07%)bytes::bytes_mut::BytesMut::from_vec (11,981,991 samples, 0.05%)bytes::bytes_mut::original_capacity_to_repr (11,981,991 samples, 0.05%)core::cmp::min (7,307,309 samples, 0.03%)core::cmp::Ord::min (7,307,309 samples, 0.03%)pow (2,468,374 samples, 0.01%)std::sys::pal::unix::time::Timespec::now (4,697,402 samples, 0.02%)<std::io::stdio::Stdout as std::io::Write>::write_all (5,967,469 samples, 0.03%)<&std::io::stdio::Stdout as std::io::Write>::write_all (5,967,469 samples, 0.03%)_fini (5,967,469 samples, 0.03%)pgdog::frontend::client::Client::run::_{{closure}} (5,967,469 samples, 0.03%)std::thread::local::LocalKey<T>::with (10,947,152 samples, 0.05%)std::thread::local::LocalKey<T>::try_with (10,947,152 samples, 0.05%)<tracing_subscriber::fmt::fmt_layer::Layer<S,N,E,W> as tracing_subscriber::layer::Layer<S>>::on_event::_{{closure}} (10,947,152 samples, 0.05%)<tokio::time::timeout::Timeout<T> as core::future::future::Future>::poll (4,979,683 samples, 0.02%)pgdog::backend::pool::connection::Connection::read::_{{closure}} (4,979,683 samples, 0.02%)pgdog::backend::pool::connection::binding::Binding::read::_{{closure}} (4,979,683 samples, 0.02%)tokio::runtime::coop::poll_proceed (3,832,463 samples, 0.02%)tokio::runtime::io::registration::Registration::poll_ready (14,468,316 samples, 0.06%)tokio::runtime::io::scheduled_io::ScheduledIo::poll_readiness (10,635,853 samples, 0.04%)tokio::loom::std::parking_lot::Mutex<T>::lock (10,635,853 samples, 0.04%)lock_api::mutex::Mutex<R,T>::lock (4,641,336 samples, 0.02%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::lock (4,641,336 samples, 0.02%)core::sync::atomic::AtomicU8::compare_exchange_weak (4,641,336 samples, 0.02%)core::sync::atomic::atomic_compare_exchange_weak (4,641,336 samples, 0.02%)tokio::runtime::scheduler::multi_thread::worker::_<impl tokio::runtime::scheduler::multi_thread::handle::Handle>::schedule_task::_{{closure}} (2,947,839 samples, 0.01%)core::ptr::drop_in_place<core::cell::RefMut<core::option::Option<alloc::boxed::Box<tokio::runtime::scheduler::multi_thread::worker::Core>>>> (2,947,839 samples, 0.01%)core::ptr::drop_in_place<core::cell::BorrowRefMut> (2,947,839 samples, 0.01%)<core::cell::BorrowRefMut as core::ops::drop::Drop>::drop (2,947,839 samples, 0.01%)core::cell::Cell<T>::set (2,947,839 samples, 0.01%)core::cell::Cell<T>::replace (2,947,839 samples, 0.01%)core::mem::replace (2,947,839 samples, 0.01%)core::ptr::write (2,947,839 samples, 0.01%)tokio::runtime::task::waker::drop_waker (7,529,666 samples, 0.03%)tokio::runtime::time::entry::TimerEntry::reset (3,870,350 samples, 0.02%)tokio::runtime::time::source::TimeSource::deadline_to_tick (3,870,350 samples, 0.02%)tokio::runtime::time::wheel::Wheel::level_for (3,839,804 samples, 0.02%)tokio::runtime::time::wheel::level_for (3,839,804 samples, 0.02%)tokio::runtime::time::wheel::Wheel::remove (7,726,654 samples, 0.03%)tokio::runtime::time::wheel::level::Level::remove_entry (3,886,850 samples, 0.02%)tokio::util::linked_list::LinkedList<L,<L as tokio::util::linked_list::Link>::Target>::remove (3,886,850 samples, 0.02%)core::cmp::PartialEq::ne (3,886,850 samples, 0.02%)<core::option::Option<T> as core::cmp::PartialEq>::eq (3,886,850 samples, 0.02%)tokio::sync::notify::Notified::poll_notified (11,943,334 samples, 0.05%)core::sync::atomic::AtomicUsize::compare_exchange (6,033,915 samples, 0.03%)core::sync::atomic::atomic_compare_exchange (6,033,915 samples, 0.03%)tokio::time::sleep::Sleep::new_timeout (10,306,016 samples, 0.04%)tokio::runtime::scheduler::Handle::current (10,306,016 samples, 0.04%)tokio::runtime::context::current::with_current (10,306,016 samples, 0.04%)std::thread::local::LocalKey<T>::try_with (10,306,016 samples, 0.04%)tokio::runtime::context::current::with_current::_{{closure}} (10,306,016 samples, 0.04%)core::option::Option<T>::map (10,306,016 samples, 0.04%)core::ops::function::FnOnce::call_once (10,306,016 samples, 0.04%)<tokio::runtime::scheduler::Handle as core::clone::Clone>::clone (10,306,016 samples, 0.04%)[unknown] (688,787,665 samples, 2.91%)[u..tracing_core::callsite::rebuild_callsite_interest (2,912,873 samples, 0.01%)pgdog::frontend::client::Client::run::_{{closure}} (2,912,873 samples, 0.01%)tokio::time::timeout::timeout (2,912,873 samples, 0.01%)tokio::time::instant::Instant::now (2,912,873 samples, 0.01%)tokio::time::instant::variant::now (2,912,873 samples, 0.01%)std::time::Instant::now (2,912,873 samples, 0.01%)std::sys::pal::unix::time::Instant::now (2,912,873 samples, 0.01%)__send (3,646,297 samples, 0.02%)__vdso_clock_gettime (229,843,799 samples, 0.97%)__x86_indirect_thunk_array (3,072,561 samples, 0.01%)_rjem_je_edata_cache_put (3,929,198 samples, 0.02%)pgdog::backend::pool::inner::Inner::maybe_check_in (3,929,198 samples, 0.02%)_rjem_je_extent_record (3,406,742 samples, 0.01%)extent_deactivate_locked (3,406,742 samples, 0.01%)extent_deactivate_locked_impl (3,406,742 samples, 0.01%)_rjem_je_eset_insert (3,406,742 samples, 0.01%)_rjem_je_pa_dalloc (3,406,742 samples, 0.01%)pgdog::frontend::client::Client::client_messages::_{{closure}} (3,406,742 samples, 0.01%)_rjem_je_sdallocx_default (5,445,480 samples, 0.02%)_rjem_je_tcache_bin_flush_stashed (5,364,153 samples, 0.02%)_rjem_je_tcache_gc_dalloc_event_handler (6,233,248 samples, 0.03%)pgdog::backend::pool::connection::Connection::connect::_{{closure}} (6,233,248 samples, 0.03%)_rjem_je_tcache_gc_event_handler (9,205,875 samples, 0.04%)tcache_event (4,313,378 samples, 0.02%)[libc.so.6] (4,313,378 samples, 0.02%)sz_size2index_usize_fastpath (9,376,420 samples, 0.04%)sz_index2size_lookup_impl (9,376,420 samples, 0.04%)_rjem_malloc (36,350,822 samples, 0.15%)imalloc_fastpath (31,538,329 samples, 0.13%)te_malloc_fastpath_ctx (4,114,899 samples, 0.02%)_rjem_sdallocx (30,717,669 samples, 0.13%)free_fastpath (26,701,246 samples, 0.11%)cache_bin_dalloc_easy (14,488,640 samples, 0.06%)cache_bin_full (14,488,640 samples, 0.06%)alloc::string::String::push (52,218,276 samples, 0.22%)alloc::vec::Vec<T,A>::push (12,105,436 samples, 0.05%)core::ptr::write (4,456,095 samples, 0.02%)base_alloc_impl (12,284,136 samples, 0.05%)base_extent_bump_alloc (12,284,136 samples, 0.05%)base_extent_bump_alloc_post (12,284,136 samples, 0.05%)sz_size2index (12,284,136 samples, 0.05%)pgdog::backend::server::Server::read::_{{closure}} (12,284,136 samples, 0.05%)bytes::bytes::promotable_even_clone (9,759,486 samples, 0.04%)bytes::bytes::promotable_even_drop (9,514,608 samples, 0.04%)<core::sync::atomic::AtomicPtr<T> as bytes::loom::sync::atomic::AtomicMut<T>>::with_mut (6,003,092 samples, 0.03%)alloc::boxed::Box<T>::new (12,214,256 samples, 0.05%)alloc::alloc::exchange_malloc (12,214,256 samples, 0.05%)<alloc::alloc::Global as core::alloc::Allocator>::allocate (12,214,256 samples, 0.05%)alloc::alloc::Global::alloc_impl (12,214,256 samples, 0.05%)alloc::alloc::alloc (12,214,256 samples, 0.05%)__rust_alloc (12,214,256 samples, 0.05%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::alloc (12,214,256 samples, 0.05%)tokio::sync::notify::Notified::poll_notified (5,097,044 samples, 0.02%)tokio::loom::std::parking_lot::Mutex<T>::lock (5,097,044 samples, 0.02%)lock_api::mutex::Mutex<R,T>::lock (5,097,044 samples, 0.02%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::lock (5,097,044 samples, 0.02%)core::sync::atomic::AtomicU8::compare_exchange_weak (5,097,044 samples, 0.02%)core::sync::atomic::atomic_compare_exchange_weak (5,097,044 samples, 0.02%)bytes::bytes::shallow_clone_vec (39,427,649 samples, 0.17%)core::sync::atomic::AtomicPtr<T>::compare_exchange (5,175,960 samples, 0.02%)core::sync::atomic::atomic_compare_exchange (5,175,960 samples, 0.02%)bytes::bytes::shallow_clone_arc (7,753,098 samples, 0.03%)core::sync::atomic::AtomicUsize::fetch_add (5,084,706 samples, 0.02%)core::sync::atomic::atomic_add (5,084,706 samples, 0.02%)bytes::bytes::shared_clone (17,866,096 samples, 0.08%)core::sync::atomic::AtomicPtr<T>::load (10,112,998 samples, 0.04%)core::sync::atomic::atomic_load (10,112,998 samples, 0.04%)core::mem::drop (3,629,255 samples, 0.02%)core::ptr::drop_in_place<alloc::boxed::Box<bytes::bytes::Shared>> (3,629,255 samples, 0.02%)core::ptr::drop_in_place<bytes::bytes::Shared> (3,629,255 samples, 0.02%)<bytes::bytes::Shared as core::ops::drop::Drop>::drop (3,629,255 samples, 0.02%)alloc::alloc::dealloc (3,629,255 samples, 0.02%)__rust_dealloc (3,629,255 samples, 0.02%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::dealloc (3,629,255 samples, 0.02%)alloc::sync::Arc<T,A>::drop_slow (3,629,255 samples, 0.02%)core::ptr::drop_in_place<alloc::sync::Weak<alloc::vec::Vec<i32>,&alloc::alloc::Global>> (3,629,255 samples, 0.02%)<alloc::sync::Weak<T,A> as core::ops::drop::Drop>::drop (3,629,255 samples, 0.02%)core::sync::atomic::AtomicUsize::fetch_sub (3,629,255 samples, 0.02%)core::sync::atomic::atomic_sub (3,629,255 samples, 0.02%)bytes::bytes::shared_drop (14,473,116 samples, 0.06%)<core::sync::atomic::AtomicPtr<T> as bytes::loom::sync::atomic::AtomicMut<T>>::with_mut (14,473,116 samples, 0.06%)bytes::bytes::shared_drop::_{{closure}} (14,473,116 samples, 0.06%)bytes::bytes::release_shared (9,572,767 samples, 0.04%)core::sync::atomic::AtomicUsize::fetch_sub (5,943,512 samples, 0.03%)core::sync::atomic::atomic_sub (5,943,512 samples, 0.03%)clock_gettime (27,686,844 samples, 0.12%)pgdog::backend::server::Server::link_client::_{{closure}} (8,629,213 samples, 0.04%)pgdog::net::parameter::Parameters::merge (8,629,213 samples, 0.04%)core::slice::<impl [T]>::contains (8,629,213 samples, 0.04%)<T as core::slice::cmp::SliceContains>::slice_contains (8,629,213 samples, 0.04%)<core::slice::iter::Iter<T> as core::iter::traits::iterator::Iterator>::any (8,629,213 samples, 0.04%)<core::slice::iter::Iter<T> as core::iter::traits::iterator::Iterator>::next (8,629,213 samples, 0.04%)<core::ptr::non_null::NonNull<T> as core::cmp::PartialEq>::eq (8,629,213 samples, 0.04%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)core::fmt::write (7,616,846 samples, 0.03%)pgdog::frontend::client::Client::run::_{{closure}} (7,616,846 samples, 0.03%)pgdog::frontend::client::Client::server_message::_{{closure}} (7,616,846 samples, 0.03%)core::ptr::drop_in_place<pgdog::net::messages::Message> (3,361,505 samples, 0.01%)core::ptr::drop_in_place<bytes::bytes::Bytes> (3,361,505 samples, 0.01%)<bytes::bytes::Bytes as core::ops::drop::Drop>::drop (3,361,505 samples, 0.01%)core::hash::BuildHasher::hash_one (10,344,456 samples, 0.04%)core::ptr::drop_in_place<(tokio::sync::notify::Notified,tokio::time::timeout::Timeout<pgdog::backend::pool::connection::Connection::read::{{closure}}>,pgdog::frontend::client::Client::buffer::{{closure}})> (16,826,526 samples, 0.07%)core::ptr::drop_in_place<tokio::time::timeout::Timeout<pgdog::backend::pool::connection::Connection::read::{{closure}}>> (4,284,090 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::pool::connection::Connection::read::{{closure}}> (4,284,090 samples, 0.02%)core::ptr::drop_in_place<alloc::vec::Vec<pgdog::backend::protocol::protocol_message::ProtocolMessage>> (4,842,979 samples, 0.02%)<alloc::vec::Vec<T,A> as core::ops::drop::Drop>::drop (4,842,979 samples, 0.02%)core::ptr::drop_in_place<[pgdog::backend::protocol::protocol_message::ProtocolMessage]> (4,842,979 samples, 0.02%)core::ptr::drop_in_place<alloc::vec::Vec<pgdog::net::messages::query::Query>> (23,263,054 samples, 0.10%)<alloc::vec::Vec<T,A> as core::ops::drop::Drop>::drop (5,504,002 samples, 0.02%)core::ptr::drop_in_place<[pgdog::net::messages::query::Query]> (5,504,002 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::error::Error> (10,840,051 samples, 0.05%)core::ptr::drop_in_place<pgdog::backend::pool::connection::Connection::parameters::{{closure}}> (7,388,100 samples, 0.03%)core::ptr::drop_in_place<pgdog::backend::pool::connection::binding::Binding::read::{{closure}}> (16,355,233 samples, 0.07%)core::ptr::drop_in_place<pgdog::backend::pool::connection::binding::Binding::send<pgdog::backend::protocol::protocol_message::ProtocolMessage>::{{closure}}> (5,281,743 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::pool::guard::Guard> (13,031,014 samples, 0.06%)<pgdog::backend::pool::guard::Guard as core::ops::drop::Drop>::drop (13,031,014 samples, 0.06%)pgdog::backend::pool::guard::Guard::cleanup (13,031,014 samples, 0.06%)[libc.so.6] (5,869,747 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::pool::pool_impl::Pool::get_internal::{{closure}}> (5,032,016 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::pool::pool_impl::Pool::maybe_healthcheck::{{closure}}> (4,068,306 samples, 0.02%)core::ptr::drop_in_place<pgdog::frontend::client::Client::buffer::{{closure}}> (13,198,200 samples, 0.06%)core::ptr::drop_in_place<pgdog::frontend::client::Client::client_messages::{{closure}}> (7,249,173 samples, 0.03%)core::ptr::drop_in_place<pgdog::frontend::client::Client::server_message::{{closure}}> (22,421,333 samples, 0.09%)core::ptr::drop_in_place<pgdog::frontend::router::parser::command::Command> (8,722,749 samples, 0.04%)core::ptr::drop_in_place<pgdog::frontend::router::parser::route::Route> (5,273,458 samples, 0.02%)core::ptr::drop_in_place<tokio::time::sleep::Sleep> (15,309,291 samples, 0.06%)core::ptr::drop_in_place<tokio::runtime::time::entry::TimerEntry> (8,343,004 samples, 0.04%)core::ptr::drop_in_place<tokio::runtime::scheduler::Handle> (4,863,246 samples, 0.02%)core::ptr::drop_in_place<alloc::sync::Arc<tokio::runtime::scheduler::multi_thread::handle::Handle>> (4,863,246 samples, 0.02%)<alloc::sync::Arc<T,A> as core::ops::drop::Drop>::drop (4,863,246 samples, 0.02%)alloc::sync::Arc<T,A>::inner (4,863,246 samples, 0.02%)core::ptr::non_null::NonNull<T>::as_ref (4,863,246 samples, 0.02%)core::ptr::drop_in_place<tokio::time::timeout::Timeout<pgdog::backend::pool::replicas::Replicas::get_internal::{{closure}}>> (14,654,975 samples, 0.06%)core::ptr::drop_in_place<pgdog::backend::pool::replicas::Replicas::get_internal::{{closure}}> (4,791,476 samples, 0.02%)_raw_write_lock_irq (8,719,840 samples, 0.04%)_raw_write_unlock_irq (4,824,032 samples, 0.02%)fdget (31,967,604 samples, 0.13%)ktime_get (61,433,016 samples, 0.26%)read_tsc (39,459,205 samples, 0.17%)_raw_spin_unlock_irqrestore (5,029,723 samples, 0.02%)hrtimer_setup_sleeper_on_stack (69,320,508 samples, 0.29%)__hrtimer_init (55,040,981 samples, 0.23%)hrtimer_sleeper_start_expires (4,129,677 samples, 0.02%)_raw_spin_lock_irqsave (26,486,147 samples, 0.11%)enqueue_hrtimer (7,588,553 samples, 0.03%)get_nohz_timer_target (24,458,022 samples, 0.10%)idle_cpu (16,106,460 samples, 0.07%)srso_alias_return_thunk (5,447,360 samples, 0.02%)srso_alias_safe_ret (5,447,360 samples, 0.02%)hrtimer_start_range_ns (216,923,605 samples, 0.92%)timerqueue_add (100,602,025 samples, 0.42%)rb_insert_color (7,408,224 samples, 0.03%)ktime_add_safe (14,833,621 samples, 0.06%)dequeue_task (18,744,599 samples, 0.08%)__cgroup_account_cputime (14,090,043 samples, 0.06%)cpuacct_charge (31,804,976 samples, 0.13%)update_curr (110,155,656 samples, 0.47%)update_curr_dl_se (10,604,262 samples, 0.04%)dl_scaled_delta_exec (8,362,282 samples, 0.04%)update_entity_lag (3,514,323 samples, 0.01%)dequeue_task_fair (160,187,485 samples, 0.68%)dequeue_entities (130,185,634 samples, 0.55%)dequeue_entity (130,185,634 samples, 0.55%)update_load_avg (4,590,390 samples, 0.02%)raw_spin_rq_lock_nested (17,084,620 samples, 0.07%)_raw_spin_lock (17,084,620 samples, 0.07%)rcu_note_context_switch (10,293,108 samples, 0.04%)sched_clock_cpu (16,556,877 samples, 0.07%)sched_clock (12,070,548 samples, 0.05%)native_sched_clock (12,070,548 samples, 0.05%)srso_alias_return_thunk (5,634,066 samples, 0.02%)srso_alias_safe_ret (5,634,066 samples, 0.02%)schedule (370,023,635 samples, 1.56%)__schedule (355,852,527 samples, 1.50%)update_rq_clock (84,218,085 samples, 0.36%)update_irq_load_avg (26,793,694 samples, 0.11%)schedule_hrtimeout_range (746,330,781 samples, 3.15%)sch..srso_alias_return_thunk (3,461,050 samples, 0.01%)srso_alias_safe_ret (3,461,050 samples, 0.01%)ktime_get_ts64 (52,628,049 samples, 0.22%)read_tsc (45,259,003 samples, 0.19%)do_epoll_wait (1,077,571,750 samples, 4.55%)do_ep..select_estimate_accuracy (123,337,406 samples, 0.52%)set_normalized_timespec64 (21,650,269 samples, 0.09%)ktime_get_ts64 (36,071,682 samples, 0.15%)read_tsc (27,573,197 samples, 0.12%)__x86_indirect_thunk_array (5,567,309 samples, 0.02%)__x64_sys_epoll_wait (1,152,728,293 samples, 4.87%)__x64_..timespec64_add_safe (8,576,722 samples, 0.04%)fdget (19,286,078 samples, 0.08%)fput (4,203,698 samples, 0.02%)__local_bh_enable_ip (8,454,352 samples, 0.04%)_raw_spin_unlock_bh (4,049,806 samples, 0.02%)release_sock (42,089,664 samples, 0.18%)tcp_release_cb (4,369,061 samples, 0.02%)tcp_recv_timestamp (26,165,101 samples, 0.11%)mem_cgroup_uncharge_skmem (96,508,152 samples, 0.41%)mod_memcg_state (96,508,152 samples, 0.41%)__mod_memcg_state (91,320,696 samples, 0.39%)cgroup_rstat_updated (10,907,248 samples, 0.05%)__sk_mem_reduce_allocated (126,160,542 samples, 0.53%)refill_stock (5,499,409 samples, 0.02%)__tcp_cleanup_rbuf (83,178,666 samples, 0.35%)__tcp_select_window (25,314,922 samples, 0.11%)__local_bh_enable_ip (2,548,245 samples, 0.01%)skb_attempt_defer_free (61,993,131 samples, 0.26%)_raw_spin_lock_bh (7,131,169 samples, 0.03%)_copy_to_iter (106,410,979 samples, 0.45%)__virt_addr_valid (24,530,519 samples, 0.10%)simple_copy_to_iter (39,692,151 samples, 0.17%)__check_object_size (39,692,151 samples, 0.17%)srso_alias_safe_ret (8,452,381 samples, 0.04%)skb_copy_datagram_iter (205,631,401 samples, 0.87%)__skb_datagram_iter (178,831,330 samples, 0.76%)srso_alias_safe_ret (6,606,370 samples, 0.03%)sock_rfree (8,906,153 samples, 0.04%)srso_alias_return_thunk (8,247,697 samples, 0.03%)srso_alias_safe_ret (8,247,697 samples, 0.03%)tcp_cleanup_rbuf (12,071,263 samples, 0.05%)tcp_rcv_space_adjust (109,865,377 samples, 0.46%)tcp_mstamp_refresh (74,154,250 samples, 0.31%)ktime_get (62,684,422 samples, 0.26%)read_tsc (47,071,786 samples, 0.20%)srso_alias_return_thunk (3,425,931 samples, 0.01%)srso_alias_safe_ret (3,425,931 samples, 0.01%)__x64_sys_recvfrom (941,668,666 samples, 3.98%)__x6..__sys_recvfrom (939,632,834 samples, 3.97%)__sy..sock_recvmsg (870,175,082 samples, 3.67%)sock..inet_recvmsg (870,175,082 samples, 3.67%)inet..tcp_recvmsg (853,790,124 samples, 3.60%)tcp_..tcp_recvmsg_locked (758,297,301 samples, 3.20%)tcp..tcp_update_recv_tstamps (12,134,198 samples, 0.05%)fdget (47,725,634 samples, 0.20%)inet_sendmsg (73,518,623 samples, 0.31%)inet_send_prepare (49,693,950 samples, 0.21%)security_socket_sendmsg (15,947,384 samples, 0.07%)bpf_lsm_socket_sendmsg (2,561,306 samples, 0.01%)srso_alias_return_thunk (5,586,483 samples, 0.02%)srso_alias_safe_ret (5,586,483 samples, 0.02%)srso_alias_safe_ret (4,153,229 samples, 0.02%)__local_bh_enable_ip (3,010,808 samples, 0.01%)_raw_spin_unlock_bh (9,184,531 samples, 0.04%)lock_sock_nested (25,055,318 samples, 0.11%)_raw_spin_lock_bh (16,658,088 samples, 0.07%)__virt_addr_valid (19,131,269 samples, 0.08%)__check_object_size (59,200,790 samples, 0.25%)check_stack_object (7,785,454 samples, 0.03%)__tcp_push_pending_frames (8,825,597 samples, 0.04%)tcp_write_xmit (8,825,597 samples, 0.04%)ktime_get (5,035,265 samples, 0.02%)_copy_from_iter (34,325,513 samples, 0.14%)sk_page_frag_refill (24,511,909 samples, 0.10%)skb_page_frag_refill (19,577,379 samples, 0.08%)srso_alias_return_thunk (9,728,145 samples, 0.04%)srso_alias_safe_ret (3,947,639 samples, 0.02%)tcp_rate_check_app_limited (5,393,846 samples, 0.02%)ipv4_mtu (33,877,029 samples, 0.14%)__rcu_read_unlock (4,592,421 samples, 0.02%)srso_alias_safe_ret (4,909,096 samples, 0.02%)tcp_send_mss (167,114,901 samples, 0.71%)tcp_current_mss (160,235,342 samples, 0.68%)tcp_established_options (39,936,912 samples, 0.17%)tcp_skb_entail (52,751,232 samples, 0.22%)tcp_chrono_start (4,904,781 samples, 0.02%)__build_skb_around (4,557,251 samples, 0.02%)kmem_cache_alloc_node_noprof (54,993,333 samples, 0.23%)memset (8,257,049 samples, 0.03%)kmalloc_reserve (70,712,835 samples, 0.30%)srso_alias_return_thunk (4,949,201 samples, 0.02%)srso_alias_safe_ret (4,949,201 samples, 0.02%)__alloc_skb (216,994,641 samples, 0.92%)kmem_cache_alloc_node_noprof (78,654,853 samples, 0.33%)memset (16,300,852 samples, 0.07%)mod_memcg_state (76,261,226 samples, 0.32%)__mod_memcg_state (65,324,918 samples, 0.28%)mem_cgroup_charge_skmem (106,068,949 samples, 0.45%)try_charge_memcg (15,772,437 samples, 0.07%)tcp_stream_alloc_skb (345,578,938 samples, 1.46%)sk_forced_mem_schedule (12,824,857 samples, 0.05%)tcp_stream_memory_free (4,086,502 samples, 0.02%)__x64_sys_sendto (1,158,748,623 samples, 4.89%)__x64_..__sys_sendto (1,158,748,623 samples, 4.89%)__sys_..tcp_sendmsg (952,708,485 samples, 4.02%)tcp_..tcp_sendmsg_locked (910,014,245 samples, 3.84%)tcp_..tcp_wmem_schedule (3,653,940 samples, 0.02%)arch_exit_to_user_mode_prepare.isra.0 (4,248,789 samples, 0.02%)do_syscall_64 (3,321,803,047 samples, 14.02%)do_syscall_64syscall_exit_to_user_mode (13,936,713 samples, 0.06%)syscall_exit_to_user_mode_prepare (7,403,432 samples, 0.03%)srso_alias_return_thunk (29,520,133 samples, 0.12%)srso_alias_safe_ret (29,520,133 samples, 0.12%)entry_SYSCALL_64_after_hwframe (3,420,506,546 samples, 14.44%)entry_SYSCALL_64_after..srso_alias_untrain_ret (23,179,587 samples, 0.10%)entry_SYSCALL_64_safe_stack (13,311,652 samples, 0.06%)epoll_wait (17,859,314 samples, 0.08%)[libc.so.6] (5,556,438 samples, 0.02%)hashbrown::map::HashMap<K,V,S,A>::find_or_find_insert_slot (3,102,117 samples, 0.01%)hashbrown::raw::RawTable<T,A>::find_or_find_insert_slot (3,102,117 samples, 0.01%)hashbrown::raw::RawTableInner::find_or_find_insert_slot_inner (3,102,117 samples, 0.01%)hashbrown::raw::RawTableInner::find_insert_slot_in_group (3,102,117 samples, 0.01%)hashbrown::control::bitmask::BitMask::lowest_set_bit (3,102,117 samples, 0.01%)<fnv::FnvHasher as core::hash::Hasher>::write (5,376,173 samples, 0.02%)hashbrown::map::HashMap<K,V,S,A>::insert (14,472,414 samples, 0.06%)hashbrown::map::make_hash (11,370,297 samples, 0.05%)core::hash::BuildHasher::hash_one (11,370,297 samples, 0.05%)core::hash::impls::<impl core::hash::Hash for &T>::hash (11,370,297 samples, 0.05%)<pgdog::net::messages::backend_key::BackendKeyData as core::hash::Hash>::hash (11,370,297 samples, 0.05%)core::hash::impls::<impl core::hash::Hash for i32>::hash (11,370,297 samples, 0.05%)core::hash::Hasher::write_i32 (11,370,297 samples, 0.05%)core::hash::Hasher::write_u32 (11,370,297 samples, 0.05%)core::num::<impl u32>::to_ne_bytes (5,994,124 samples, 0.03%)pgdog::backend::pool::cleanup::Cleanup::new (36,449,629 samples, 0.15%)pgdog::backend::pool::cleanup::Cleanup::none (4,418,412 samples, 0.02%)pgdog::backend::pool::connection::Connection::connect::_{{closure}} (5,116,499 samples, 0.02%)pgdog::backend::pool::connection::Connection::disconnect (12,410,850 samples, 0.05%)pgdog::backend::pool::connection::binding::Binding::disconnect (12,377,714 samples, 0.05%)core::option::Option<T>::take (4,898,443 samples, 0.02%)core::mem::replace (4,898,443 samples, 0.02%)core::ptr::read (4,898,443 samples, 0.02%)pgdog::backend::pool::connection::Connection::send::_{{closure}} (24,779,752 samples, 0.10%)pgdog::backend::pool::connection::binding::Binding::send::_{{closure}} (13,605,691 samples, 0.06%)entry_SYSCALL_64 (4,753,848 samples, 0.02%)pgdog::backend::pool::connection::Connection::try_conn::_{{closure}} (20,247,574 samples, 0.09%)pgdog::backend::pool::cluster::Cluster::replica::_{{closure}} (14,918,117 samples, 0.06%)core::slice::<impl [T]>::get (14,918,117 samples, 0.06%)<usize as core::slice::index::SliceIndex<[T]>>::get (14,918,117 samples, 0.06%)pgdog::backend::pool::healthcheck::Healtcheck::healthcheck::_{{closure}} (26,290,085 samples, 0.11%)pgdog::backend::server::Server::healthcheck_age (4,391,772 samples, 0.02%)std::time::Instant::duration_since (4,391,772 samples, 0.02%)core::option::Option<T>::unwrap_or_default (4,391,772 samples, 0.02%)pgdog::backend::server::Server::done (5,787,241 samples, 0.02%)pgdog::backend::pool::inner::Inner::maybe_check_in (13,721,651 samples, 0.06%)pgdog::backend::stats::Stats::reset_last_checkout (3,886,317 samples, 0.02%)pgdog::backend::pool::inner::Inner::take (4,418,412 samples, 0.02%)alloc::collections::vec_deque::VecDeque<T,A>::pop_back (4,418,412 samples, 0.02%)pgdog::backend::pool::pool_impl::Pool::get_internal::_{{closure}} (44,540,076 samples, 0.19%)pgdog::backend::pool::pool_impl::Pool::maybe_healthcheck::_{{closure}} (4,658,748 samples, 0.02%)pgdog::backend::pool::healthcheck::Healtcheck::conditional (4,658,748 samples, 0.02%)<F as core::future::into_future::IntoFuture>::into_future (4,975,867 samples, 0.02%)pgdog::backend::pool::replicas::Replicas::get_internal::_{{closure}} (45,380,365 samples, 0.19%)pgdog::backend::pool::pool_impl::Pool::get::_{{closure}} (18,060,283 samples, 0.08%)pgdog::backend::pool::shard::Shard::replica::_{{closure}} (72,278,436 samples, 0.31%)pgdog::backend::pool::replicas::Replicas::get::_{{closure}} (53,536,367 samples, 0.23%)<tokio::time::timeout::Timeout<T> as core::future::future::Future>::poll (48,560,500 samples, 0.21%)tokio::runtime::coop::has_budget_remaining (3,180,135 samples, 0.01%)core::slice::<impl [T]>::contains (5,287,170 samples, 0.02%)pgdog::backend::server::Server::link_client::_{{closure}} (38,068,649 samples, 0.16%)pgdog::net::parameter::Parameters::merge (23,808,563 samples, 0.10%)std::collections::hash::map::HashMap<K,V,S>::get (3,187,264 samples, 0.01%)hashbrown::map::HashMap<K,V,S,A>::get (3,187,264 samples, 0.01%)hashbrown::map::HashMap<K,V,S,A>::get_inner (3,187,264 samples, 0.01%)hashbrown::map::make_hash (3,187,264 samples, 0.01%)pgdog::backend::server::Server::read::_{{closure}} (62,754,556 samples, 0.26%)pgdog::backend::prepared_statements::PreparedStatements::forward (4,671,660 samples, 0.02%)entry_SYSCALL_64 (4,043,183 samples, 0.02%)pgdog::backend::server::Server::send::_{{closure}} (17,165,942 samples, 0.07%)pgdog::backend::server::Server::send_one::_{{closure}} (5,588,244 samples, 0.02%)<core::iter::adapters::flatten::Flatten<I> as core::iter::traits::iterator::Iterator>::next (3,216,819 samples, 0.01%)<core::iter::adapters::flatten::FlattenCompat<I,U> as core::iter::traits::iterator::Iterator>::next (3,216,819 samples, 0.01%)pgdog::backend::stats::Stats::update (3,317,875 samples, 0.01%)<alloc::sync::Arc<T,A> as core::clone::Clone>::clone (4,099,862 samples, 0.02%)core::sync::atomic::AtomicUsize::fetch_add (4,099,862 samples, 0.02%)core::sync::atomic::atomic_add (4,099,862 samples, 0.02%)core::result::Result<T,E>::unwrap_or_else (3,548,870 samples, 0.01%)pgdog::config::config (14,654,827 samples, 0.06%)arc_swap::ArcSwapAny<T,S>::load (10,554,965 samples, 0.04%)<arc_swap::strategy::hybrid::HybridStrategy<Cfg> as arc_swap::strategy::sealed::InnerStrategy<T>>::load (7,315,129 samples, 0.03%)arc_swap::debt::list::LocalNode::with (7,315,129 samples, 0.03%)std::thread::local::LocalKey<T>::try_with (3,766,259 samples, 0.02%)arc_swap::debt::list::LocalNode::with::_{{closure}} (3,766,259 samples, 0.02%)<usize as core::iter::traits::accum::Sum>::sum::_{{closure}} (4,512,005 samples, 0.02%)pgdog::frontend::buffer::Buffer::len (15,689,916 samples, 0.07%)core::iter::traits::iterator::Iterator::sum (15,689,916 samples, 0.07%)<usize as core::iter::traits::accum::Sum>::sum (15,689,916 samples, 0.07%)<core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::fold (15,689,916 samples, 0.07%)<core::slice::iter::Iter<T> as core::iter::traits::iterator::Iterator>::fold (15,689,916 samples, 0.07%)core::iter::adapters::map::map_fold::_{{closure}} (15,689,916 samples, 0.07%)pgdog::frontend::buffer::Buffer::len::_{{closure}} (11,177,911 samples, 0.05%)pgdog::backend::protocol::protocol_message::ProtocolMessage::len (11,177,911 samples, 0.05%)pgdog::net::messages::parse::Parse::len (4,167,105 samples, 0.02%)<alloc::sync::Arc<T,A> as core::ops::deref::Deref>::deref (4,167,105 samples, 0.02%)alloc::sync::Arc<T,A>::inner (4,167,105 samples, 0.02%)core::ptr::non_null::NonNull<T>::as_ref (4,167,105 samples, 0.02%)<F as core::future::into_future::IntoFuture>::into_future (6,260,356 samples, 0.03%)<core::slice::iter::Iter<T> as core::iter::traits::iterator::Iterator>::next (4,578,921 samples, 0.02%)<core::ptr::non_null::NonNull<T> as core::cmp::PartialEq>::eq (4,578,921 samples, 0.02%)pgdog::backend::pool::connection::Connection::link_client::_{{closure}} (24,076,086 samples, 0.10%)pgdog::backend::pool::connection::binding::Binding::link_client::_{{closure}} (19,036,741 samples, 0.08%)<tokio::time::timeout::Timeout<T> as core::future::future::Future>::poll (28,589,669 samples, 0.12%)tokio::runtime::coop::has_budget_remaining (4,513,583 samples, 0.02%)tokio::runtime::context::budget (4,513,583 samples, 0.02%)std::thread::local::LocalKey<T>::try_with (4,513,583 samples, 0.02%)core::ops::function::FnOnce::call_once (4,513,583 samples, 0.02%)tokio::runtime::context::CONTEXT::_{{constant}}::_{{closure}} (4,513,583 samples, 0.02%)std::sys::thread_local::native::eager::Storage<T>::get (4,513,583 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::pool::connection::Connection::send<pgdog::backend::protocol::protocol_message::ProtocolMessage>::{{closure}}> (3,404,574 samples, 0.01%)pgdog::frontend::buffer::Buffer::copy (5,443,583 samples, 0.02%)core::option::Option<T>::map (5,443,583 samples, 0.02%)pgdog::frontend::buffer::Buffer::copy::_{{closure}} (5,443,583 samples, 0.02%)<pgdog::backend::protocol::protocol_message::ProtocolMessage as pgdog::net::messages::Protocol>::code (5,443,583 samples, 0.02%)pgdog::frontend::buffer::Buffer::executable (10,514,388 samples, 0.04%)<core::slice::iter::Iter<T> as core::iter::traits::iterator::Iterator>::any (10,514,388 samples, 0.04%)pgdog::frontend::buffer::Buffer::executable::_{{closure}} (8,397,288 samples, 0.04%)<pgdog::backend::protocol::protocol_message::ProtocolMessage as pgdog::net::messages::Protocol>::code (8,397,288 samples, 0.04%)<core::result::Result<T,E> as core::ops::try_trait::Try>::branch (4,192,476 samples, 0.02%)pgdog::frontend::client::inner::Inner::command (17,185,375 samples, 0.07%)core::option::Option<T>::map (12,373,428 samples, 0.05%)pgdog::frontend::client::inner::Inner::command::_{{closure}} (12,373,428 samples, 0.05%)pgdog::frontend::router::Router::query (12,373,428 samples, 0.05%)pgdog::frontend::router::parser::query::QueryParser::parse (12,373,428 samples, 0.05%)pgdog::frontend::buffer::Buffer::parameters (4,448,275 samples, 0.02%)core::ptr::drop_in_place<alloc::vec::Vec<&pgdog::backend::pool::address::Address>> (8,455,832 samples, 0.04%)core::ptr::drop_in_place<alloc::raw_vec::RawVec<&pgdog::backend::pool::address::Address>> (8,455,832 samples, 0.04%)<alloc::raw_vec::RawVec<T,A> as core::ops::drop::Drop>::drop (8,455,832 samples, 0.04%)alloc::raw_vec::RawVecInner<A>::deallocate (8,455,832 samples, 0.04%)alloc::raw_vec::RawVecInner<A>::current_memory (8,455,832 samples, 0.04%)core::num::<impl usize>::unchecked_mul (5,368,642 samples, 0.02%)core::result::Result<T,E>::is_ok (5,922,522 samples, 0.03%)pgdog::backend::pool::connection::Connection::addr (4,127,200 samples, 0.02%)alloc::alloc::exchange_malloc (4,127,200 samples, 0.02%)<alloc::alloc::Global as core::alloc::Allocator>::allocate (4,127,200 samples, 0.02%)alloc::alloc::Global::alloc_impl (4,127,200 samples, 0.02%)alloc::alloc::alloc (4,127,200 samples, 0.02%)__rust_alloc (4,127,200 samples, 0.02%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::alloc (4,127,200 samples, 0.02%)pgdog::frontend::router::Router::route (26,914,172 samples, 0.11%)pgdog::frontend::router::parser::query::QueryParser::route (26,914,172 samples, 0.11%)pgdog::frontend::client::inner::Inner::connect::_{{closure}} (62,713,326 samples, 0.26%)pgdog::frontend::stats::Stats::connected (4,706,872 samples, 0.02%)pgdog::frontend::client::inner::Inner::connected (3,763,823 samples, 0.02%)pgdog::backend::pool::connection::Connection::connected (3,763,823 samples, 0.02%)pgdog::backend::pool::connection::binding::Binding::connected (3,763,823 samples, 0.02%)core::option::Option<T>::is_some (3,763,823 samples, 0.02%)pgdog::frontend::stats::Stats::received (6,927,037 samples, 0.03%)std::time::Instant::now (6,927,037 samples, 0.03%)std::sys::pal::unix::time::Instant::now (6,927,037 samples, 0.03%)pgdog::frontend::client::Client::client_messages::_{{closure}} (192,794,745 samples, 0.81%)tokio::time::timeout::timeout (18,914,519 samples, 0.08%)tokio::time::instant::Instant::checked_add (4,212,259 samples, 0.02%)std::time::SystemTime::checked_add (4,212,259 samples, 0.02%)std::sys::pal::unix::time::SystemTime::checked_add_duration (4,212,259 samples, 0.02%)std::sys::pal::unix::time::Timespec::checked_add_duration (4,212,259 samples, 0.02%)core::num::<impl i64>::checked_add_unsigned (4,212,259 samples, 0.02%)core::num::<impl i64>::overflowing_add_unsigned (4,212,259 samples, 0.02%)<tokio::sync::notify::Notified as core::future::future::Future>::poll (4,641,996 samples, 0.02%)<core::result::Result<T,E> as core::ops::try_trait::Try>::branch (14,639,200 samples, 0.06%)<pgdog::backend::protocol::protocol_message::ProtocolMessage as pgdog::net::messages::FromBytes>::from_bytes (13,148,030 samples, 0.06%)<core::result::Result<T,E> as core::ops::try_trait::Try>::branch (3,577,983 samples, 0.02%)<pgdog::net::messages::Message as pgdog::net::messages::ToBytes>::to_bytes (6,279,772 samples, 0.03%)<bytes::bytes::Bytes as core::clone::Clone>::clone (6,279,772 samples, 0.03%)alloc::vec::Vec<T,A>::push (7,544,404 samples, 0.03%)core::ptr::write (4,007,848 samples, 0.02%)core::ptr::drop_in_place<pgdog::net::messages::Message> (4,590,846 samples, 0.02%)core::ptr::drop_in_place<bytes::bytes::Bytes> (4,590,846 samples, 0.02%)<bytes::bytes::Bytes as core::ops::drop::Drop>::drop (4,590,846 samples, 0.02%)pgdog::frontend::buffer::Buffer::new (5,422,046 samples, 0.02%)pgdog::frontend::client::Client::buffer::_{{closure}} (99,770,836 samples, 0.42%)tracing_core::metadata::LevelFilter::current (5,079,694 samples, 0.02%)core::sync::atomic::AtomicUsize::load (5,079,694 samples, 0.02%)core::sync::atomic::atomic_load (5,079,694 samples, 0.02%)core::ops::function::FnOnce::call_once (5,211,330 samples, 0.02%)tokio::runtime::context::CONTEXT::_{{constant}}::_{{closure}} (5,211,330 samples, 0.02%)std::sys::thread_local::native::eager::Storage<T>::get (5,211,330 samples, 0.02%)core::cell::Cell<T>::get (5,211,330 samples, 0.02%)<core::future::poll_fn::PollFn<F> as core::future::future::Future>::poll (140,561,682 samples, 0.59%)pgdog::frontend::client::Client::run::_{{closure}}::_{{closure}} (140,561,682 samples, 0.59%)tokio::macros::support::thread_rng_n (8,085,602 samples, 0.03%)tokio::runtime::context::thread_rng_n (8,085,602 samples, 0.03%)std::thread::local::LocalKey<T>::with (8,085,602 samples, 0.03%)std::thread::local::LocalKey<T>::try_with (8,085,602 samples, 0.03%)tokio::runtime::context::thread_rng_n::_{{closure}} (2,874,272 samples, 0.01%)core::cell::Cell<T>::set (2,874,272 samples, 0.01%)core::cell::Cell<T>::replace (2,874,272 samples, 0.01%)core::mem::replace (2,874,272 samples, 0.01%)core::ptr::write (2,874,272 samples, 0.01%)<core::result::Result<T,E> as core::ops::try_trait::Try>::branch (5,525,550 samples, 0.02%)<pgdog::net::messages::Message as pgdog::net::messages::Protocol>::code (7,676,778 samples, 0.03%)core::ptr::drop_in_place<pgdog::frontend::client::inner::InnerBorrow> (5,902,798 samples, 0.02%)core::ptr::drop_in_place<pgdog::net::parameter::Parameters> (9,541,685 samples, 0.04%)core::ptr::drop_in_place<std::collections::hash::map::HashMap<alloc::string::String,alloc::string::String>> (9,541,685 samples, 0.04%)core::ptr::drop_in_place<hashbrown::map::HashMap<alloc::string::String,alloc::string::String,std::hash::random::RandomState>> (9,541,685 samples, 0.04%)core::ptr::drop_in_place<hashbrown::raw::RawTable<(alloc::string::String,alloc::string::String)>> (9,541,685 samples, 0.04%)<hashbrown::raw::RawTable<T,A> as core::ops::drop::Drop>::drop (9,541,685 samples, 0.04%)hashbrown::raw::RawTableInner::drop_inner_table (9,541,685 samples, 0.04%)hashbrown::raw::RawTableInner::free_buckets (4,641,336 samples, 0.02%)hashbrown::raw::RawTableInner::allocation_info (4,641,336 samples, 0.02%)hashbrown::raw::TableLayout::calculate_layout_for (4,641,336 samples, 0.02%)core::num::<impl usize>::checked_mul (4,641,336 samples, 0.02%)core::num::<impl usize>::overflowing_mul (4,641,336 samples, 0.02%)pgdog::backend::pool::connection::Connection::changed_params (4,782,676 samples, 0.02%)pgdog::backend::pool::connection::binding::Binding::changed_params (4,782,676 samples, 0.02%)<pgdog::net::parameter::Parameters as core::clone::Clone>::clone (4,782,676 samples, 0.02%)<std::collections::hash::map::HashMap<K,V,S> as core::clone::Clone>::clone (4,782,676 samples, 0.02%)pgdog::backend::pool::connection::Connection::done (7,718,978 samples, 0.03%)pgdog::backend::pool::connection::binding::Binding::done (7,718,978 samples, 0.03%)<tracing_core::metadata::Level as core::cmp::PartialOrd<tracing_core::metadata::LevelFilter>>::le (4,749,866 samples, 0.02%)pgdog::frontend::client::Client::server_message::_{{closure}} (115,404,933 samples, 0.49%)pgdog::net::stream::Stream::send_flush::_{{closure}} (17,803,841 samples, 0.08%)tracing_core::metadata::LevelFilter::current (6,145,398 samples, 0.03%)core::sync::atomic::AtomicUsize::load (6,145,398 samples, 0.03%)core::sync::atomic::atomic_load (6,145,398 samples, 0.03%)pgdog::frontend::client::Client::run::_{{closure}} (284,997,012 samples, 1.20%)tokio::time::timeout::timeout (4,725,079 samples, 0.02%)tokio::time::instant::Instant::checked_add (4,725,079 samples, 0.02%)std::time::SystemTime::checked_add (4,725,079 samples, 0.02%)std::sys::pal::unix::time::SystemTime::checked_add_duration (4,725,079 samples, 0.02%)std::sys::pal::unix::time::Timespec::checked_add_duration (4,725,079 samples, 0.02%)core::num::<impl i64>::checked_add_unsigned (4,725,079 samples, 0.02%)core::num::<impl i64>::overflowing_add_unsigned (4,725,079 samples, 0.02%)core::num::<impl i64>::overflowing_add (4,725,079 samples, 0.02%)pgdog::frontend::comms::Comms::stats (26,374,767 samples, 0.11%)std::collections::hash::map::HashMap<K,V,S>::get_mut (8,955,349 samples, 0.04%)hashbrown::map::HashMap<K,V,S,A>::get_mut (8,955,349 samples, 0.04%)hashbrown::map::HashMap<K,V,S,A>::get_inner_mut (4,488,485 samples, 0.02%)hashbrown::raw::RawTable<T,A>::get_mut (4,488,485 samples, 0.02%)hashbrown::raw::RawTable<T,A>::find (4,488,485 samples, 0.02%)hashbrown::raw::RawTableInner::find_inner (4,488,485 samples, 0.02%)core::intrinsics::likely (4,488,485 samples, 0.02%)core::ptr::drop_in_place<pgdog::backend::pool::cluster::ShardingSchema> (9,355,844 samples, 0.04%)core::ptr::drop_in_place<pgdog::backend::replication::sharded_tables::ShardedTables> (9,355,844 samples, 0.04%)core::ptr::drop_in_place<alloc::sync::Arc<alloc::vec::Vec<pgdog::config::ShardedTable>>> (9,355,844 samples, 0.04%)<alloc::sync::Arc<T,A> as core::ops::drop::Drop>::drop (9,355,844 samples, 0.04%)pgdog::backend::pool::cluster::Cluster::sharding_schema (9,879,393 samples, 0.04%)<pgdog::backend::replication::sharded_tables::ShardedTables as core::clone::Clone>::clone (9,879,393 samples, 0.04%)<alloc::sync::Arc<T,A> as core::clone::Clone>::clone (9,879,393 samples, 0.04%)core::sync::atomic::AtomicUsize::fetch_add (5,268,790 samples, 0.02%)core::sync::atomic::atomic_add (5,268,790 samples, 0.02%)pgdog::frontend::router::parser::query::QueryParser::query (31,482,719 samples, 0.13%)pgdog::config::PreparedStatements::full (7,174,005 samples, 0.03%)alloc::string::String::with_capacity (4,432,364 samples, 0.02%)alloc::vec::Vec<T>::with_capacity (4,432,364 samples, 0.02%)alloc::vec::Vec<T,A>::with_capacity_in (4,432,364 samples, 0.02%)alloc::raw_vec::RawVec<T,A>::with_capacity_in (4,432,364 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::with_capacity_in (4,432,364 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::try_allocate_in (4,432,364 samples, 0.02%)bytes::buf::buf_impl::Buf::get_u8 (15,181,464 samples, 0.06%)<bytes::bytes::Bytes as bytes::buf::buf_impl::Buf>::advance (8,600,002 samples, 0.04%)bytes::bytes::Bytes::inc_start (8,600,002 samples, 0.04%)pgdog::net::c_string_buf (62,300,355 samples, 0.26%)pgdog::net::c_string_buf_len (3,601,016 samples, 0.02%)<tokio::io::util::read_exact::ReadExact<A> as core::future::future::Future>::poll (4,441,699 samples, 0.02%)tokio::io::read_buf::ReadBuf::filled (10,957,435 samples, 0.05%)core::slice::index::<impl core::ops::index::Index<I> for [T]>::index (5,815,940 samples, 0.02%)<core::ops::range::RangeTo<usize> as core::slice::index::SliceIndex<[T]>>::index (5,815,940 samples, 0.02%)<core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::index (5,815,940 samples, 0.02%)<tokio::io::util::read_int::ReadI32<R> as core::future::future::Future>::poll (22,457,186 samples, 0.09%)tokio::io::read_buf::ReadBuf::new (4,485,332 samples, 0.02%)<&mut T as tokio::io::async_read::AsyncRead>::poll_read (3,140,148 samples, 0.01%)tokio::io::read_buf::ReadBuf::filled (8,752,945 samples, 0.04%)core::slice::index::<impl core::ops::index::Index<I> for [T]>::index (4,082,591 samples, 0.02%)<core::ops::range::RangeTo<usize> as core::slice::index::SliceIndex<[T]>>::index (4,082,591 samples, 0.02%)<core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::index (4,082,591 samples, 0.02%)<tokio::io::util::read_int::ReadU8<R> as core::future::future::Future>::poll (29,885,328 samples, 0.13%)tokio::io::read_buf::ReadBuf::new (4,177,691 samples, 0.02%)bytes::buf::buf_mut::BufMut::put_i32 (4,009,951 samples, 0.02%)<bytes::bytes_mut::BytesMut as bytes::buf::buf_mut::BufMut>::put_slice (4,009,951 samples, 0.02%)bytes::bytes_mut::BytesMut::extend_from_slice (4,009,951 samples, 0.02%)<bytes::bytes_mut::BytesMut as bytes::buf::buf_mut::BufMut>::advance_mut (4,009,951 samples, 0.02%)bytes::bytes_mut::BytesMut::freeze (8,093,315 samples, 0.03%)<T as core::convert::Into<U>>::into (8,093,315 samples, 0.03%)<bytes::bytes::Bytes as core::convert::From<alloc::vec::Vec<u8>>>::from (8,093,315 samples, 0.03%)<bytes::bytes::Bytes as core::convert::From<alloc::boxed::Box<[u8]>>>::from (5,092,251 samples, 0.02%)bytes::bytes_mut::BytesMut::resize (10,069,822 samples, 0.04%)core::intrinsics::write_bytes (4,164,976 samples, 0.02%)alloc::vec::Vec<T>::with_capacity (18,243,405 samples, 0.08%)alloc::vec::Vec<T,A>::with_capacity_in (18,243,405 samples, 0.08%)alloc::raw_vec::RawVec<T,A>::with_capacity_in (18,243,405 samples, 0.08%)alloc::raw_vec::RawVecInner<A>::with_capacity_in (18,243,405 samples, 0.08%)alloc::raw_vec::RawVecInner<A>::try_allocate_in (18,243,405 samples, 0.08%)<alloc::alloc::Global as core::alloc::Allocator>::allocate (18,243,405 samples, 0.08%)alloc::alloc::Global::alloc_impl (18,243,405 samples, 0.08%)alloc::alloc::alloc (18,243,405 samples, 0.08%)__rust_alloc (18,243,405 samples, 0.08%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::alloc (18,243,405 samples, 0.08%)pgdog::backend::pool::shard::Shard::replica::_{{closure}} (18,243,405 samples, 0.08%)pgdog::backend::pool::replicas::Replicas::get::_{{closure}} (14,925,691 samples, 0.06%)<tokio::time::timeout::Timeout<T> as core::future::future::Future>::poll (14,925,691 samples, 0.06%)pgdog::backend::pool::replicas::Replicas::get_internal::_{{closure}} (14,925,691 samples, 0.06%)pgdog::backend::pool::pool_impl::Pool::get::_{{closure}} (10,251,009 samples, 0.04%)bytes::bytes_mut::BytesMut::with_capacity (21,740,282 samples, 0.09%)bytes::bytes_mut::BytesMut::from_vec (3,496,877 samples, 0.01%)pgdog::net::stream::Stream::read::_{{closure}} (144,919,557 samples, 0.61%)core::slice::index::<impl core::ops::index::IndexMut<I> for [T]>::index_mut (3,851,316 samples, 0.02%)<core::ops::range::RangeFrom<usize> as core::slice::index::SliceIndex<[T]>>::index_mut (3,851,316 samples, 0.02%)pgdog::net::stream::Stream::send::_{{closure}} (21,722,901 samples, 0.09%)<pgdog::net::messages::Message as pgdog::net::messages::ToBytes>::to_bytes (6,260,356 samples, 0.03%)<bytes::bytes::Bytes as core::clone::Clone>::clone (6,260,356 samples, 0.03%)recv (28,744,366 samples, 0.12%)std::sys::pal::unix::time::Timespec::now (25,692,443 samples, 0.11%)core::result::Result<T,E>::unwrap (4,820,763 samples, 0.02%)std::sys::pal::unix::time::Timespec::sub_timespec (20,703,684 samples, 0.09%)syscall_return_via_sysret (10,881,226 samples, 0.05%)tokio::io::util::buf_writer::BufWriter<W>::flush_buf (8,657,966 samples, 0.04%)alloc::vec::Vec<T,A>::drain (4,558,578 samples, 0.02%)core::slice::index::range (4,558,578 samples, 0.02%)mio::poll::Poll::poll (6,253,484 samples, 0.03%)mio::sys::unix::selector::Selector::select (6,253,484 samples, 0.03%)tokio::runtime::io::driver::Driver::turn (16,497,336 samples, 0.07%)tokio::io::ready::Ready::from_mio (5,150,769 samples, 0.02%)mio::event::event::Event::is_readable (5,150,769 samples, 0.02%)mio::sys::unix::selector::event::is_readable (5,150,769 samples, 0.02%)core::ptr::drop_in_place<tokio::runtime::coop::RestoreOnPending> (3,171,057 samples, 0.01%)<tokio::runtime::coop::RestoreOnPending as core::ops::drop::Drop>::drop (3,171,057 samples, 0.01%)tokio::loom::std::parking_lot::Mutex<T>::lock (5,741,406 samples, 0.02%)lock_api::mutex::Mutex<R,T>::lock (5,741,406 samples, 0.02%)<parking_lot::raw_mutex::RawMutex as lock_api::mutex::RawMutex>::lock (5,741,406 samples, 0.02%)core::sync::atomic::AtomicU8::compare_exchange_weak (5,741,406 samples, 0.02%)core::sync::atomic::atomic_compare_exchange_weak (5,741,406 samples, 0.02%)tokio::runtime::io::registration::Registration::poll_ready (20,436,413 samples, 0.09%)tokio::runtime::io::scheduled_io::ScheduledIo::poll_readiness (10,271,856 samples, 0.04%)tokio::runtime::io::driver::Direction::mask (4,530,450 samples, 0.02%)entry_SYSCALL_64 (4,530,450 samples, 0.02%)tokio::runtime::io::scheduled_io::ScheduledIo::wake (2,858,628 samples, 0.01%)tokio::runtime::scheduler::multi_thread::worker::Context::run_task (3,114,224 samples, 0.01%)tokio::runtime::coop::budget (3,114,224 samples, 0.01%)tokio::runtime::coop::with_budget (3,114,224 samples, 0.01%)tokio::runtime::scheduler::multi_thread::worker::Context::run_task::_{{closure}} (3,114,224 samples, 0.01%)tokio::runtime::task::LocalNotified<S>::run (3,114,224 samples, 0.01%)tokio::runtime::task::raw::RawTask::poll (3,114,224 samples, 0.01%)tokio::runtime::task::raw::poll (3,114,224 samples, 0.01%)tokio::runtime::task::harness::Harness<T,S>::poll (3,114,224 samples, 0.01%)tokio::runtime::task::harness::Harness<T,S>::poll_inner (3,114,224 samples, 0.01%)tokio::runtime::task::harness::poll_future (3,114,224 samples, 0.01%)std::panic::catch_unwind (3,114,224 samples, 0.01%)std::panicking::try (3,114,224 samples, 0.01%)std::panicking::try::do_call (3,114,224 samples, 0.01%)<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once (3,114,224 samples, 0.01%)tokio::runtime::task::harness::poll_future::_{{closure}} (3,114,224 samples, 0.01%)tokio::runtime::task::core::Core<T,S>::poll (3,114,224 samples, 0.01%)tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut (3,114,224 samples, 0.01%)tokio::runtime::task::core::Core<T,S>::poll::_{{closure}} (3,114,224 samples, 0.01%)<tokio_util::task::task_tracker::TrackedFuture<F> as core::future::future::Future>::poll (3,114,224 samples, 0.01%)pgdog::frontend::listener::Listener::listen::_{{closure}}::_{{closure}} (3,114,224 samples, 0.01%)pgdog::frontend::listener::Listener::handle_client::_{{closure}} (3,114,224 samples, 0.01%)pgdog::frontend::client::Client::spawn::_{{closure}} (3,114,224 samples, 0.01%)pgdog::frontend::client::Client::spawn_internal::_{{closure}} (3,114,224 samples, 0.01%)pgdog::frontend::client::Client::run::_{{closure}} (3,114,224 samples, 0.01%)pgdog::frontend::client::Client::client_messages::_{{closure}} (3,114,224 samples, 0.01%)pgdog::frontend::client::inner::Inner::connect::_{{closure}} (3,114,224 samples, 0.01%)pgdog::backend::pool::connection::Connection::connect::_{{closure}} (3,114,224 samples, 0.01%)pgdog::backend::pool::connection::Connection::try_conn::_{{closure}} (3,114,224 samples, 0.01%)pgdog::backend::pool::cluster::Cluster::replica::_{{closure}} (3,114,224 samples, 0.01%)bytes::bytes::promotable_even_clone (3,114,224 samples, 0.01%)<tracing_core::metadata::Level as core::cmp::PartialOrd<tracing_core::metadata::LevelFilter>>::le (4,797,751 samples, 0.02%)[libc.so.6] (14,654,468 samples, 0.06%)_rjem_sdallocx (9,301,659 samples, 0.04%)free_fastpath (9,301,659 samples, 0.04%)cache_bin_dalloc_easy (4,314,213 samples, 0.02%)bytes::bytes::shared_drop (3,597,693 samples, 0.02%)<core::sync::atomic::AtomicPtr<T> as bytes::loom::sync::atomic::AtomicMut<T>>::with_mut (3,597,693 samples, 0.02%)bytes::bytes::shared_drop::_{{closure}} (3,597,693 samples, 0.02%)__x86_indirect_thunk_array (8,922,018 samples, 0.04%)fput (4,207,923 samples, 0.02%)__local_bh_enable_ip (11,739,842 samples, 0.05%)_raw_spin_unlock_bh (4,517,736 samples, 0.02%)release_sock (8,053,044 samples, 0.03%)_raw_spin_lock_bh (3,093,224 samples, 0.01%)__check_object_size (16,681,383 samples, 0.07%)__virt_addr_valid (4,950,474 samples, 0.02%)__ip_finish_output (25,608,208 samples, 0.11%)ip_skb_dst_mtu (25,608,208 samples, 0.11%)__rcu_read_unlock (2,762,405 samples, 0.01%)__sk_dst_check (52,643,260 samples, 0.22%)ipv4_dst_check (23,628,938 samples, 0.10%)__rcu_read_lock (6,788,490 samples, 0.03%)ip_finish_output (5,085,909 samples, 0.02%)irqtime_account_irq (77,116,888 samples, 0.33%)sched_clock_cpu (27,305,382 samples, 0.12%)sched_clock (23,108,610 samples, 0.10%)native_sched_clock (23,108,610 samples, 0.10%)__netif_receive_skb (9,058,703 samples, 0.04%)__netif_receive_skb_core.constprop.0 (68,874,779 samples, 0.29%)__rcu_read_unlock (9,919,802 samples, 0.04%)raw_local_deliver (18,211,937 samples, 0.08%)srso_alias_return_thunk (2,706,790 samples, 0.01%)srso_alias_safe_ret (2,706,790 samples, 0.01%)inet_ehashfn (9,379,975 samples, 0.04%)__inet_lookup_established (86,551,960 samples, 0.37%)srso_alias_safe_ret (6,376,707 samples, 0.03%)_raw_spin_lock (6,650,931 samples, 0.03%)_raw_spin_unlock (11,697,830 samples, 0.05%)__rcu_read_lock (8,517,352 samples, 0.04%)sk_filter_trim_cap (51,339,590 samples, 0.22%)security_sock_rcv_skb (4,808,380 samples, 0.02%)bpf_lsm_socket_sock_rcv_skb (4,808,380 samples, 0.02%)sock_put (6,413,561 samples, 0.03%)srso_alias_return_thunk (3,214,954 samples, 0.01%)srso_alias_safe_ret (3,214,954 samples, 0.01%)tcp_inbound_hash (14,435,588 samples, 0.06%)tcp_do_parse_auth_options (4,526,780 samples, 0.02%)ipv4_dst_check (21,141,766 samples, 0.09%)__rcu_read_unlock (3,543,096 samples, 0.01%)srso_alias_return_thunk (3,170,517 samples, 0.01%)srso_alias_safe_ret (3,170,517 samples, 0.01%)__rcu_read_unlock (6,767,352 samples, 0.03%)__tcp_ack_snd_check (3,560,960 samples, 0.02%)asm_sysvec_apic_timer_interrupt (2,940,082 samples, 0.01%)enqueue_timer (8,844,990 samples, 0.04%)__mod_timer (24,633,857 samples, 0.10%)lock_timer_base (3,524,126 samples, 0.01%)_raw_spin_lock_irqsave (3,524,126 samples, 0.01%)sk_reset_timer (36,452,182 samples, 0.15%)mod_timer (7,062,389 samples, 0.03%)__rcu_read_lock (4,422,516 samples, 0.02%)default_wake_function (5,183,748 samples, 0.02%)_raw_spin_lock_irqsave (20,499,252 samples, 0.09%)__rcu_read_lock (3,187,264 samples, 0.01%)select_task_rq_fair (41,766,919 samples, 0.18%)available_idle_cpu (8,333,551 samples, 0.04%)call_function_single_prep_ipi (15,503,689 samples, 0.07%)ep_autoremove_wake_function (209,325,760 samples, 0.88%)try_to_wake_up (190,968,898 samples, 0.81%)ttwu_queue_wakelist (71,760,014 samples, 0.30%)__smp_call_single_queue (40,556,105 samples, 0.17%)llist_add_batch (15,771,791 samples, 0.07%)__wake_up_common (258,009,475 samples, 1.09%)srso_alias_return_thunk (2,767,177 samples, 0.01%)__wake_up_sync (267,670,855 samples, 1.13%)_raw_spin_lock_irqsave (4,388,769 samples, 0.02%)__x86_indirect_thunk_array (3,407,538 samples, 0.01%)_raw_read_lock_irqsave (26,513,559 samples, 0.11%)_raw_read_unlock_irqrestore (7,229,398 samples, 0.03%)__wake_up_common (402,538,667 samples, 1.70%)ep_poll_callback (358,359,157 samples, 1.51%)_raw_spin_unlock_irqrestore (4,957,944 samples, 0.02%)sock_def_readable (438,434,577 samples, 1.85%)s..__wake_up_sync_key (423,978,105 samples, 1.79%)_.._raw_spin_lock_irqsave (12,161,193 samples, 0.05%)srso_alias_return_thunk (10,998,273 samples, 0.05%)srso_alias_safe_ret (10,998,273 samples, 0.05%)skb_release_data (20,959,017 samples, 0.09%)kmem_cache_free (5,195,265 samples, 0.02%)__slab_free (5,195,265 samples, 0.02%)slab_update_freelist.isra.0 (5,195,265 samples, 0.02%)__kfree_skb (31,609,038 samples, 0.13%)skb_release_head_state (4,074,811 samples, 0.02%)cubictcp_acked (10,573,328 samples, 0.04%)cubictcp_cong_avoid (6,212,801 samples, 0.03%)kfree_skbmem (17,084,602 samples, 0.07%)kmem_cache_free (10,574,971 samples, 0.04%)__slab_free (10,574,971 samples, 0.04%)slab_update_freelist.isra.0 (4,851,059 samples, 0.02%)rb_erase (8,850,422 samples, 0.04%)rb_first (14,860,180 samples, 0.06%)rb_next (11,078,369 samples, 0.05%)srso_alias_return_thunk (14,829,057 samples, 0.06%)srso_alias_safe_ret (14,829,057 samples, 0.06%)tcp_ack_tstamp (14,363,445 samples, 0.06%)tcp_ack_update_rtt (12,111,591 samples, 0.05%)tcp_newly_delivered (31,200,000 samples, 0.13%)tcp_rack_advance (11,196,567 samples, 0.05%)tcp_rack_update_reo_wnd (6,653,981 samples, 0.03%)tcp_rate_gen (14,328,504 samples, 0.06%)tcp_rate_skb_delivered (5,208,720 samples, 0.02%)tcp_rearm_rto (8,822,464 samples, 0.04%)tcp_schedule_loss_probe.part.0 (7,150,673 samples, 0.03%)tcp_ack (436,999,425 samples, 1.84%)t..tcp_update_pacing_rate (39,656,924 samples, 0.17%)tcp_check_space (10,417,976 samples, 0.04%)tcp_data_ready (11,139,666 samples, 0.05%)tcp_event_data_recv (16,043,222 samples, 0.07%)tcp_mstamp_refresh (31,148,477 samples, 0.13%)ktime_get (27,785,497 samples, 0.12%)read_tsc (21,761,187 samples, 0.09%)tcp_queue_rcv (33,606,020 samples, 0.14%)tcp_v4_do_rcv (1,195,701,092 samples, 5.05%)tcp_v4..tcp_rcv_established (1,148,768,867 samples, 4.85%)tcp_rc..tcp_send_delayed_ack (9,258,373 samples, 0.04%)ip_protocol_deliver_rcu (1,504,636,040 samples, 6.35%)ip_proto..tcp_v4_rcv (1,450,722,541 samples, 6.12%)tcp_v4_r..tcp_v4_fill_cb (4,447,384 samples, 0.02%)ip_local_deliver_finish (1,568,088,701 samples, 6.62%)ip_local_..ktime_get_with_offset (35,773,511 samples, 0.15%)read_tsc (19,288,680 samples, 0.08%)ip_rcv_core (16,663,667 samples, 0.07%)__netif_receive_skb_one_core (1,693,761,322 samples, 7.15%)__netif_re..ip_rcv (49,148,071 samples, 0.21%)ip_rcv_finish_core (32,484,404 samples, 0.14%)__rcu_read_unlock (3,474,349 samples, 0.01%)_raw_spin_lock_irq (7,728,931 samples, 0.03%)__napi_poll (1,766,192,042 samples, 7.46%)__napi_pollprocess_backlog (1,766,192,042 samples, 7.46%)process_ba.._raw_spin_unlock_irq (15,668,003 samples, 0.07%)_raw_spin_lock (4,929,470 samples, 0.02%)kfree_skbmem (5,166,448 samples, 0.02%)kmem_cache_free (27,586,163 samples, 0.12%)free_frozen_page_commit (3,154,376 samples, 0.01%)free_pcppages_bulk (3,154,376 samples, 0.01%)__free_one_page (3,154,376 samples, 0.01%)free_frozen_pages (8,607,795 samples, 0.04%)get_pfnblock_flags_mask (5,453,419 samples, 0.02%)kmem_cache_free (23,266,276 samples, 0.10%)net_rx_action (1,965,656,290 samples, 8.30%)net_rx_actionnapi_consume_skb (80,846,442 samples, 0.34%)skb_release_data (69,989,651 samples, 0.30%)skb_free_head (4,753,001 samples, 0.02%)do_softirq.part.0 (2,118,370,985 samples, 8.94%)do_softirq.pa..handle_softirqs (2,084,847,159 samples, 8.80%)handle_softi..srso_alias_return_thunk (4,669,221 samples, 0.02%)__local_bh_enable_ip (2,132,254,793 samples, 9.00%)__local_bh_en..srso_alias_return_thunk (5,858,912 samples, 0.02%)srso_alias_safe_ret (5,858,912 samples, 0.02%)_raw_spin_lock_irqsave (5,449,446 samples, 0.02%)_raw_spin_unlock_irqrestore (7,749,449 samples, 0.03%)__netif_rx (72,137,521 samples, 0.30%)netif_rx_internal (72,137,521 samples, 0.30%)enqueue_to_backlog (63,731,828 samples, 0.27%)srso_alias_return_thunk (4,289,911 samples, 0.02%)__rcu_read_unlock (4,252,040 samples, 0.02%)eth_type_trans (22,906,323 samples, 0.10%)sk_free (5,312,401 samples, 0.02%)skb_clone_tx_timestamp (16,177,887 samples, 0.07%)srso_alias_return_thunk (5,342,550 samples, 0.02%)srso_alias_return_thunk (10,145,847 samples, 0.04%)srso_alias_safe_ret (10,145,847 samples, 0.04%)dev_hard_start_xmit (198,042,737 samples, 0.84%)loopback_xmit (177,155,246 samples, 0.75%)tcp_wfree (20,258,576 samples, 0.09%)srso_alias_return_thunk (7,116,082 samples, 0.03%)srso_alias_safe_ret (7,116,082 samples, 0.03%)__dev_queue_xmit (2,397,548,415 samples, 10.12%)__dev_queue_xmitvalidate_xmit_skb (35,649,912 samples, 0.15%)netif_skb_features (5,565,082 samples, 0.02%)srso_alias_return_thunk (5,565,082 samples, 0.02%)srso_alias_safe_ret (5,565,082 samples, 0.02%)ip_finish_output2 (2,493,583,287 samples, 10.53%)ip_finish_outpu..srso_alias_safe_ret (5,768,379 samples, 0.02%)__ip_queue_xmit (2,656,363,778 samples, 11.21%)__ip_queue_xmitip_local_out (9,069,549 samples, 0.04%)__ip_local_out (9,069,549 samples, 0.04%)ip_send_check (9,069,549 samples, 0.04%)__skb_clone (22,935,078 samples, 0.10%)__tcp_select_window (5,277,007 samples, 0.02%)asm_sysvec_apic_timer_interrupt (5,229,776 samples, 0.02%)bpf_skops_write_hdr_opt.isra.0 (4,296,672 samples, 0.02%)skb_clone (18,266,193 samples, 0.08%)tcp_options_write (5,972,666 samples, 0.03%)tcp_rate_skb_sent (11,707,844 samples, 0.05%)tcp_update_skb_after_send (22,735,697 samples, 0.10%)__tcp_transmit_skb (2,901,723,520 samples, 12.25%)__tcp_transmit_skbtcp_v4_send_check (15,404,172 samples, 0.07%)ktime_get (27,450,194 samples, 0.12%)read_tsc (14,640,603 samples, 0.06%)tcp_check_space (11,820,511 samples, 0.05%)tcp_chrono_stop (10,042,794 samples, 0.04%)rb_insert_color (6,514,583 samples, 0.03%)sk_reset_timer (22,898,074 samples, 0.10%)__mod_timer (22,898,074 samples, 0.10%)tcp_rbtree_insert (14,570,607 samples, 0.06%)tcp_event_new_data_sent (86,853,784 samples, 0.37%)tcp_rearm_rto (6,529,817 samples, 0.03%)__usecs_to_jiffies (16,010,848 samples, 0.07%)rb_first (4,895,711 samples, 0.02%)tcp_schedule_loss_probe.part.0 (112,882,961 samples, 0.48%)sk_reset_timer (8,928,622 samples, 0.04%)__mod_timer (8,928,622 samples, 0.04%)__tcp_push_pending_frames (3,260,506,433 samples, 13.77%)__tcp_push_pending_fr..tcp_write_xmit (3,246,955,342 samples, 13.71%)tcp_write_xmittcp_tso_segs (10,946,305 samples, 0.05%)_copy_from_iter (17,206,272 samples, 0.07%)mod_memcg_state (5,064,836 samples, 0.02%)__mod_memcg_state (5,064,836 samples, 0.02%)cgroup_rstat_updated (5,064,836 samples, 0.02%)__x64_sys_sendto (3,438,923,528 samples, 14.52%)__x64_sys_sendto__sys_sendto (3,438,923,528 samples, 14.52%)__sys_sendtotcp_sendmsg (3,406,703,644 samples, 14.38%)tcp_sendmsgtcp_sendmsg_locked (3,364,711,311 samples, 14.21%)tcp_sendmsg_lockedtcp_stream_alloc_skb (8,158,060 samples, 0.03%)mem_cgroup_charge_skmem (8,158,060 samples, 0.03%)try_charge_memcg (3,093,224 samples, 0.01%)asm_sysvec_apic_timer_interrupt (4,392,609 samples, 0.02%)sysvec_apic_timer_interrupt (4,392,609 samples, 0.02%)__sysvec_apic_timer_interrupt (4,392,609 samples, 0.02%)hrtimer_interrupt (4,392,609 samples, 0.02%)__hrtimer_run_queues (4,392,609 samples, 0.02%)tick_nohz_handler (4,392,609 samples, 0.02%)update_process_times (4,392,609 samples, 0.02%)sched_tick (4,392,609 samples, 0.02%)task_tick_fair (4,392,609 samples, 0.02%)update_curr (4,392,609 samples, 0.02%)srso_alias_return_thunk (4,392,609 samples, 0.02%)srso_alias_safe_ret (4,392,609 samples, 0.02%)entry_SYSCALL_64_after_hwframe (3,528,515,915 samples, 14.90%)entry_SYSCALL_64_after_..do_syscall_64 (3,528,515,915 samples, 14.90%)do_syscall_64syscall_exit_to_user_mode (59,556,595 samples, 0.25%)arch_exit_to_user_mode_prepare.isra.0 (34,921,720 samples, 0.15%)[libc.so.6] (3,581,509,460 samples, 15.12%)[libc.so.6][libc.so.6] (3,576,724,387 samples, 15.10%)[libc.so.6][libc.so.6] (3,559,186,601 samples, 15.03%)[libc.so.6]syscall_return_via_sysret (11,187,592 samples, 0.05%)__send (3,593,445,347 samples, 15.17%)__send__vdso_clock_gettime (5,084,601 samples, 0.02%)<tokio::net::tcp::stream::TcpStream as tokio::io::async_write::AsyncWrite>::poll_write (3,606,455,726 samples, 15.23%)<tokio::net::tcp::strea..tokio::net::tcp::stream::TcpStream::poll_write_priv (3,596,949,081 samples, 15.19%)tokio::net::tcp::stream..tokio::io::poll_evented::PollEvented<E>::poll_write (3,596,949,081 samples, 15.19%)tokio::io::poll_evented..<&mio::net::tcp::stream::TcpStream as std::io::Write>::write (3,593,447,503 samples, 15.17%)<&mio::net::tcp::stream..mio::io_source::IoSource<T>::do_io (3,593,447,503 samples, 15.17%)mio::io_source::IoSourc..mio::sys::unix::selector::stateless_io_source::IoSourceState::do_io (3,593,447,503 samples, 15.17%)mio::sys::unix::selecto..<&mio::net::tcp::stream::TcpStream as std::io::Write>::write::_{{closure}} (3,593,447,503 samples, 15.17%)<&mio::net::tcp::stream..<&std::net::tcp::TcpStream as std::io::Write>::write (3,593,447,503 samples, 15.17%)<&std::net::tcp::TcpStr..std::sys::net::connection::socket::TcpStream::write (3,593,447,503 samples, 15.17%)std::sys::net::connecti..pgdog::backend::server::Server::flush::_{{closure}} (3,630,897,943 samples, 15.33%)pgdog::backend::server:..tokio::io::util::buf_writer::BufWriter<W>::flush_buf (3,623,617,351 samples, 15.30%)tokio::io::util::buf_wr..alloc::sync::Arc<T,A>::drop_slow (3,678,929 samples, 0.02%)core::ptr::drop_in_place<rustls::msgs::base::PayloadU16> (3,678,929 samples, 0.02%)core::ptr::drop_in_place<alloc::vec::Vec<u8>> (3,678,929 samples, 0.02%)core::ptr::drop_in_place<alloc::raw_vec::RawVec<u8>> (3,678,929 samples, 0.02%)<alloc::raw_vec::RawVec<T,A> as core::ops::drop::Drop>::drop (3,678,929 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::deallocate (3,678,929 samples, 0.02%)<alloc::alloc::Global as core::alloc::Allocator>::deallocate (3,678,929 samples, 0.02%)alloc::alloc::dealloc (3,678,929 samples, 0.02%)__rust_dealloc (3,678,929 samples, 0.02%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::dealloc (3,678,929 samples, 0.02%)<core::iter::adapters::flatten::Flatten<I> as core::iter::traits::iterator::Iterator>::next (6,906,899 samples, 0.03%)<core::iter::adapters::flatten::FlattenCompat<I,U> as core::iter::traits::iterator::Iterator>::next (6,906,899 samples, 0.03%)[libc.so.6] (6,906,899 samples, 0.03%)[libc.so.6] (18,251,198 samples, 0.08%)_rjem_malloc (5,059,058 samples, 0.02%)imalloc_fastpath (5,059,058 samples, 0.02%)sz_size2index_usize_fastpath (5,059,058 samples, 0.02%)sz_index2size_lookup_impl (5,059,058 samples, 0.02%)_rjem_sdallocx (3,511,516 samples, 0.01%)free_fastpath (3,511,516 samples, 0.01%)cache_bin_dalloc_easy (3,511,516 samples, 0.01%)[libc.so.6] (5,597,441 samples, 0.02%)bytes::bytes::shared_drop (9,581,912 samples, 0.04%)<core::sync::atomic::AtomicPtr<T> as bytes::loom::sync::atomic::AtomicMut<T>>::with_mut (9,581,912 samples, 0.04%)bytes::bytes::shared_drop::_{{closure}} (9,581,912 samples, 0.04%)bytes::bytes::release_shared (9,581,912 samples, 0.04%)core::mem::drop (9,581,912 samples, 0.04%)core::ptr::drop_in_place<alloc::boxed::Box<bytes::bytes::Shared>> (9,581,912 samples, 0.04%)core::ptr::drop_in_place<bytes::bytes::Shared> (9,581,912 samples, 0.04%)<bytes::bytes::Shared as core::ops::drop::Drop>::drop (9,581,912 samples, 0.04%)alloc::alloc::dealloc (9,581,912 samples, 0.04%)__rust_dealloc (9,581,912 samples, 0.04%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::dealloc (9,581,912 samples, 0.04%)pgdog::frontend::comms::Comms::stats (3,984,471 samples, 0.02%)core::ptr::drop_in_place<alloc::vec::Vec<pgdog::net::messages::query::Query>> (3,344,381 samples, 0.01%)core::ptr::drop_in_place<pgdog::backend::protocol::protocol_message::ProtocolMessage> (4,943,080 samples, 0.02%)core::ptr::drop_in_place<pgdog::net::messages::parse::Parse> (4,943,080 samples, 0.02%)core::ptr::drop_in_place<alloc::sync::Arc<alloc::string::String>> (4,943,080 samples, 0.02%)<alloc::sync::Arc<T,A> as core::ops::drop::Drop>::drop (4,943,080 samples, 0.02%)alloc::sync::Arc<T,A>::drop_slow (4,943,080 samples, 0.02%)core::ptr::drop_in_place<rustls::msgs::base::PayloadU16> (4,943,080 samples, 0.02%)core::ptr::drop_in_place<alloc::vec::Vec<u8>> (4,943,080 samples, 0.02%)core::ptr::drop_in_place<alloc::raw_vec::RawVec<u8>> (4,943,080 samples, 0.02%)<alloc::raw_vec::RawVec<T,A> as core::ops::drop::Drop>::drop (4,943,080 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::deallocate (4,943,080 samples, 0.02%)<alloc::alloc::Global as core::alloc::Allocator>::deallocate (4,943,080 samples, 0.02%)alloc::alloc::dealloc (4,943,080 samples, 0.02%)__rust_dealloc (4,943,080 samples, 0.02%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::dealloc (4,943,080 samples, 0.02%)hashbrown::map::HashMap<K,V,S,A>::insert (4,943,080 samples, 0.02%)pgdog::backend::pool::pool_impl::Pool::get_internal::_{{closure}} (4,703,882 samples, 0.02%)pgdog::backend::stats::Stats::state (4,382,924 samples, 0.02%)pgdog::backend::stats::Stats::update (4,382,924 samples, 0.02%)pgdog::backend::stats::update (4,382,924 samples, 0.02%)[libc.so.6] (4,382,924 samples, 0.02%)pgdog::backend::pool::connection::Connection::send::_{{closure}} (3,744,667,221 samples, 15.81%)pgdog::backend::pool::co..pgdog::backend::pool::connection::binding::Binding::send::_{{closure}} (3,744,667,221 samples, 15.81%)pgdog::backend::pool::co..pgdog::backend::server::Server::send::_{{closure}} (3,744,667,221 samples, 15.81%)pgdog::backend::server::..pgdog::backend::server::Server::send_one::_{{closure}} (66,445,050 samples, 0.28%)pgdog::net::stream::Stream::send::_{{closure}} (5,500,897 samples, 0.02%)<pgdog::backend::protocol::protocol_message::ProtocolMessage as pgdog::net::messages::ToBytes>::to_bytes (5,500,897 samples, 0.02%)pgdog::net::messages::payload::Payload::freeze (5,500,897 samples, 0.02%)<pgdog::net::messages::payload::Payload as pgdog::net::messages::ToBytes>::to_bytes (5,500,897 samples, 0.02%)<bytes::bytes_mut::BytesMut as bytes::buf::buf_mut::BufMut>::put_slice (5,500,897 samples, 0.02%)bytes::bytes_mut::BytesMut::extend_from_slice (5,500,897 samples, 0.02%)<bytes::bytes_mut::BytesMut as bytes::buf::buf_mut::BufMut>::advance_mut (5,500,897 samples, 0.02%)asm_sysvec_reschedule_ipi (5,500,897 samples, 0.02%)irqentry_exit_to_user_mode (5,500,897 samples, 0.02%)schedule (5,500,897 samples, 0.02%)__schedule (5,500,897 samples, 0.02%)psi_task_switch (5,500,897 samples, 0.02%)psi_group_change (5,500,897 samples, 0.02%)sched_clock_cpu (5,500,897 samples, 0.02%)sched_clock (5,500,897 samples, 0.02%)native_sched_clock (5,500,897 samples, 0.02%)<pgdog::net::messages::describe::Describe as pgdog::net::messages::FromBytes>::from_bytes (5,019,076 samples, 0.02%)core::iter::traits::iterator::Iterator::collect (4,708,707 samples, 0.02%)<alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter (4,708,707 samples, 0.02%)<alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter (4,708,707 samples, 0.02%)<alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter (4,708,707 samples, 0.02%)alloc::vec::Vec<T>::with_capacity (4,708,707 samples, 0.02%)alloc::vec::Vec<T,A>::with_capacity_in (4,708,707 samples, 0.02%)alloc::raw_vec::RawVec<T,A>::with_capacity_in (4,708,707 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::with_capacity_in (4,708,707 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::try_allocate_in (4,708,707 samples, 0.02%)<alloc::alloc::Global as core::alloc::Allocator>::allocate (4,708,707 samples, 0.02%)alloc::alloc::Global::alloc_impl (4,708,707 samples, 0.02%)alloc::alloc::alloc (4,708,707 samples, 0.02%)__rust_alloc (4,708,707 samples, 0.02%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::alloc (4,708,707 samples, 0.02%)_rjem_malloc (4,708,707 samples, 0.02%)imalloc_fastpath (4,708,707 samples, 0.02%)cache_bin_alloc_easy (4,708,707 samples, 0.02%)cache_bin_alloc_impl (4,708,707 samples, 0.02%)<tokio::time::timeout::Timeout<T> as core::future::future::Future>::poll (8,951,882 samples, 0.04%)pgdog::backend::pool::replicas::Replicas::get_internal::_{{closure}} (8,951,882 samples, 0.04%)pgdog::backend::pool::pool_impl::Pool::get::_{{closure}} (4,243,175 samples, 0.02%)pgdog::backend::pool::pool_impl::Pool::get_internal::_{{closure}} (4,243,175 samples, 0.02%)pgdog::backend::pool::pool_impl::Pool::maybe_healthcheck::_{{closure}} (4,243,175 samples, 0.02%)pgdog::backend::pool::healthcheck::Healtcheck::healthcheck::_{{closure}} (4,243,175 samples, 0.02%)std::time::Instant::now (4,243,175 samples, 0.02%)std::sys::pal::unix::time::Instant::now (4,243,175 samples, 0.02%)[libc.so.6] (4,243,175 samples, 0.02%)pgdog::frontend::client::Client::client_messages::_{{closure}} (3,762,927,592 samples, 15.89%)pgdog::frontend::client:..pgdog::frontend::client::inner::Inner::connect::_{{closure}} (18,260,371 samples, 0.08%)pgdog::backend::pool::connection::Connection::connect::_{{closure}} (18,260,371 samples, 0.08%)pgdog::backend::pool::connection::Connection::try_conn::_{{closure}} (18,260,371 samples, 0.08%)pgdog::backend::pool::cluster::Cluster::replica::_{{closure}} (18,260,371 samples, 0.08%)pgdog::backend::pool::shard::Shard::replica::_{{closure}} (18,260,371 samples, 0.08%)pgdog::backend::pool::replicas::Replicas::get::_{{closure}} (18,260,371 samples, 0.08%)_rjem_malloc (4,289,413 samples, 0.02%)imalloc_fastpath (4,289,413 samples, 0.02%)pgdog::backend::pool::cleanup::Cleanup::new (4,915,255 samples, 0.02%)hashbrown::map::make_hash (21,476,546 samples, 0.09%)core::hash::BuildHasher::hash_one (21,476,546 samples, 0.09%)core::hash::impls::<impl core::hash::Hash for &T>::hash (21,476,546 samples, 0.09%)<pgdog::net::messages::backend_key::BackendKeyData as core::hash::Hash>::hash (21,476,546 samples, 0.09%)core::hash::impls::<impl core::hash::Hash for i32>::hash (21,476,546 samples, 0.09%)core::hash::Hasher::write_i32 (21,476,546 samples, 0.09%)core::hash::Hasher::write_u32 (21,476,546 samples, 0.09%)<fnv::FnvHasher as core::hash::Hasher>::write (21,476,546 samples, 0.09%)core::num::<impl u64>::wrapping_mul (17,200,163 samples, 0.07%)core::intrinsics::likely (11,495,692 samples, 0.05%)hashbrown::control::group::sse2::Group::match_tag (16,396,439 samples, 0.07%)core::core_arch::x86::sse2::_mm_movemask_epi8 (16,396,439 samples, 0.07%)hashbrown::raw::RawTable<T,A>::find (43,809,596 samples, 0.18%)hashbrown::raw::RawTableInner::find_inner (43,809,596 samples, 0.18%)hashbrown::control::tag::Tag::full (15,917,465 samples, 0.07%)pgdog::backend::pool::inner::Inner::maybe_check_in (86,829,331 samples, 0.37%)pgdog::backend::pool::taken::Taken::check_in (79,147,314 samples, 0.33%)std::collections::hash::map::HashMap<K,V,S>::remove (79,147,314 samples, 0.33%)hashbrown::map::HashMap<K,V,S,A>::remove (79,147,314 samples, 0.33%)hashbrown::map::HashMap<K,V,S,A>::remove_entry (73,565,560 samples, 0.31%)hashbrown::raw::RawTable<T,A>::remove_entry (52,089,014 samples, 0.22%)hashbrown::raw::RawTable<T,A>::remove (8,279,418 samples, 0.03%)hashbrown::raw::RawTable<T,A>::erase_no_drop (8,279,418 samples, 0.03%)hashbrown::raw::RawTableInner::erase (8,279,418 samples, 0.03%)core::num::<impl usize>::wrapping_sub (3,490,459 samples, 0.01%)std::time::Instant::now (45,181,364 samples, 0.19%)std::sys::pal::unix::time::Instant::now (45,181,364 samples, 0.19%)std::sys::pal::unix::time::Timespec::now (45,181,364 samples, 0.19%)clock_gettime (41,669,609 samples, 0.18%)__vdso_clock_gettime (25,913,186 samples, 0.11%)<pgdog::backend::pool::guard::Guard as core::ops::drop::Drop>::drop (159,946,262 samples, 0.68%)pgdog::backend::pool::guard::Guard::cleanup (159,946,262 samples, 0.68%)pgdog::backend::pool::pool_impl::Pool::checkin (155,031,007 samples, 0.65%)tokio::sync::notify::Notify::notify_one (9,271,338 samples, 0.04%)tokio::sync::notify::Notify::notify_with_strategy (9,271,338 samples, 0.04%)pgdog::frontend::client::Client::server_message::_{{closure}} (164,902,805 samples, 0.70%)pgdog::frontend::client::inner::Inner::disconnect (164,902,805 samples, 0.70%)pgdog::backend::pool::connection::Connection::disconnect (164,902,805 samples, 0.70%)pgdog::backend::pool::connection::binding::Binding::disconnect (164,902,805 samples, 0.70%)core::mem::drop (164,902,805 samples, 0.70%)core::ptr::drop_in_place<core::option::Option<pgdog::backend::pool::guard::Guard>> (164,902,805 samples, 0.70%)core::ptr::drop_in_place<pgdog::backend::pool::guard::Guard> (164,902,805 samples, 0.70%)core::ptr::drop_in_place<pgdog::backend::pool::pool_impl::Pool> (4,956,543 samples, 0.02%)core::ptr::drop_in_place<alloc::sync::Arc<pgdog::backend::pool::pool_impl::InnerSync>> (4,956,543 samples, 0.02%)<alloc::sync::Arc<T,A> as core::ops::drop::Drop>::drop (4,956,543 samples, 0.02%)alloc::sync::Arc<T,A>::inner (4,956,543 samples, 0.02%)core::ptr::non_null::NonNull<T>::as_ref (4,956,543 samples, 0.02%)tokio::runtime::task::raw::poll (3,933,333,326 samples, 16.61%)tokio::runtime::task::raw:..tokio::runtime::task::harness::Harness<T,S>::poll (3,933,333,326 samples, 16.61%)tokio::runtime::task::harn..tokio::runtime::task::harness::Harness<T,S>::poll_inner (3,933,333,326 samples, 16.61%)tokio::runtime::task::harn..tokio::runtime::task::harness::poll_future (3,933,333,326 samples, 16.61%)tokio::runtime::task::harn..std::panic::catch_unwind (3,933,333,326 samples, 16.61%)std::panic::catch_unwindstd::panicking::try (3,933,333,326 samples, 16.61%)std::panicking::trystd::panicking::try::do_call (3,933,333,326 samples, 16.61%)std::panicking::try::do_ca..<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once (3,933,333,326 samples, 16.61%)<core::panic::unwind_safe:..tokio::runtime::task::harness::poll_future::_{{closure}} (3,933,333,326 samples, 16.61%)tokio::runtime::task::harn..tokio::runtime::task::core::Core<T,S>::poll (3,933,333,326 samples, 16.61%)tokio::runtime::task::core..tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut (3,933,333,326 samples, 16.61%)tokio::loom::std::unsafe_c..tokio::runtime::task::core::Core<T,S>::poll::_{{closure}} (3,933,333,326 samples, 16.61%)tokio::runtime::task::core..<tokio_util::task::task_tracker::TrackedFuture<F> as core::future::future::Future>::poll (3,933,333,326 samples, 16.61%)<tokio_util::task::task_tr..pgdog::frontend::listener::Listener::listen::_{{closure}}::_{{closure}} (3,933,333,326 samples, 16.61%)pgdog::frontend::listener:..pgdog::frontend::listener::Listener::handle_client::_{{closure}} (3,933,333,326 samples, 16.61%)pgdog::frontend::listener:..pgdog::frontend::client::Client::spawn::_{{closure}} (3,933,333,326 samples, 16.61%)pgdog::frontend::client::C..pgdog::frontend::client::Client::spawn_internal::_{{closure}} (3,933,333,326 samples, 16.61%)pgdog::frontend::client::C..pgdog::frontend::client::Client::run::_{{closure}} (3,933,333,326 samples, 16.61%)pgdog::frontend::client::C..pgdog::net::stream::Stream::read::_{{closure}} (5,502,929 samples, 0.02%)bytes::bytes_mut::BytesMut::with_capacity (5,502,929 samples, 0.02%)alloc::vec::Vec<T>::with_capacity (5,502,929 samples, 0.02%)alloc::vec::Vec<T,A>::with_capacity_in (5,502,929 samples, 0.02%)alloc::raw_vec::RawVec<T,A>::with_capacity_in (5,502,929 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::with_capacity_in (5,502,929 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::try_allocate_in (5,502,929 samples, 0.02%)<alloc::alloc::Global as core::alloc::Allocator>::allocate (5,502,929 samples, 0.02%)alloc::alloc::Global::alloc_impl (5,502,929 samples, 0.02%)alloc::alloc::alloc (5,502,929 samples, 0.02%)__rust_alloc (5,502,929 samples, 0.02%)<tikv_jemallocator::Jemalloc as core::alloc::global::GlobalAlloc>::alloc (5,502,929 samples, 0.02%)<pgdog::net::stream::Stream as tokio::io::async_read::AsyncRead>::poll_read (5,502,929 samples, 0.02%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (5,502,929 samples, 0.02%)<tokio::io::util::buf_reader::BufReader<R> as tokio::io::async_read::AsyncRead>::poll_read (5,502,929 samples, 0.02%)tokio::io::read_buf::ReadBuf::put_slice (5,502,929 samples, 0.02%)core::ptr::mut_ptr::<impl *mut T>::copy_from_nonoverlapping (5,502,929 samples, 0.02%)core::intrinsics::copy_nonoverlapping (5,502,929 samples, 0.02%)<tokio::net::tcp::stream::TcpStream as tokio::io::async_read::AsyncRead>::poll_read (5,502,929 samples, 0.02%)tokio::net::tcp::stream::TcpStream::poll_read_priv (5,502,929 samples, 0.02%)tokio::io::poll_evented::PollEvented<E>::poll_read (5,502,929 samples, 0.02%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read (5,502,929 samples, 0.02%)mio::io_source::IoSource<T>::do_io (5,502,929 samples, 0.02%)mio::sys::unix::selector::stateless_io_source::IoSourceState::do_io (5,502,929 samples, 0.02%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read::_{{closure}} (5,502,929 samples, 0.02%)<&std::net::tcp::TcpStream as std::io::Read>::read (5,502,929 samples, 0.02%)std::sys::net::connection::socket::TcpStream::read (5,502,929 samples, 0.02%)std::sys::net::connection::socket::unix::Socket::read (5,502,929 samples, 0.02%)std::sys::net::connection::socket::unix::Socket::recv_with_flags (5,502,929 samples, 0.02%)recv (5,502,929 samples, 0.02%)[libc.so.6] (5,502,929 samples, 0.02%)_rjem_je_tcache_gc_event_handler (5,502,929 samples, 0.02%)tcache_event (5,502,929 samples, 0.02%)pgdog::frontend::client::Client::client_messages::_{{closure}} (5,502,929 samples, 0.02%)tokio::runtime::task::raw::schedule (8,488,823 samples, 0.04%)tokio::runtime::task::waker::wake_by_val (4,581,500 samples, 0.02%)tokio::runtime::task::harness::<impl tokio::runtime::task::raw::RawTask>::wake_by_val (4,581,500 samples, 0.02%)tokio::runtime::time::Driver::park_internal (4,989,402 samples, 0.02%)tokio::runtime::time::_<impl tokio::runtime::time::handle::Handle>::process_at_time::_{{closure}} (4,353,992 samples, 0.02%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::process_at_sharded_time (4,353,992 samples, 0.02%)tokio::runtime::time::wheel::Wheel::poll (4,353,992 samples, 0.02%)tokio::runtime::time::entry::TimerEntry::inner (9,610,778 samples, 0.04%)tokio::runtime::time::entry::generate_shard_id (4,345,224 samples, 0.02%)tokio::runtime::context::with_scheduler (4,345,224 samples, 0.02%)std::thread::local::LocalKey<T>::try_with (4,345,224 samples, 0.02%)tokio::runtime::context::with_scheduler::_{{closure}} (4,345,224 samples, 0.02%)tokio::runtime::time::handle::Handle::is_shutdown (2,762,033 samples, 0.01%)tokio::runtime::time::Inner::is_shutdown (2,762,033 samples, 0.01%)core::sync::atomic::AtomicBool::load (2,762,033 samples, 0.01%)core::sync::atomic::atomic_load (2,762,033 samples, 0.01%)tokio::runtime::time::wheel::Wheel::level_for (4,421,093 samples, 0.02%)tokio::runtime::time::wheel::level_for (4,421,093 samples, 0.02%)core::num::<impl u64>::leading_zeros (4,421,093 samples, 0.02%)tokio::runtime::time::<impl tokio::runtime::time::handle::Handle>::reregister (11,568,953 samples, 0.05%)tokio::runtime::time::wheel::Wheel::insert (8,806,920 samples, 0.04%)tokio::runtime::time::wheel::level::Level::add_entry (4,385,827 samples, 0.02%)tokio::util::linked_list::LinkedList<L,<L as tokio::util::linked_list::Link>::Target>::push_front (4,385,827 samples, 0.02%)tokio::runtime::time::entry::TimerEntry::reset (25,820,632 samples, 0.11%)tokio::runtime::time::source::TimeSource::deadline_to_tick (8,495,335 samples, 0.04%)tokio::runtime::time::source::TimeSource::instant_to_tick (8,495,335 samples, 0.04%)core::time::Duration::as_millis (8,495,335 samples, 0.04%)tokio::runtime::time::wheel::Wheel::next_expiration (4,766,020 samples, 0.02%)tokio::runtime::time::entry::TimerShared::cached_when (5,101,920 samples, 0.02%)core::sync::atomic::AtomicU64::load (5,101,920 samples, 0.02%)core::sync::atomic::atomic_load (5,101,920 samples, 0.02%)tokio::runtime::time::wheel::Wheel::remove (17,032,888 samples, 0.07%)tokio::runtime::time::wheel::Wheel::level_for (5,497,710 samples, 0.02%)tokio::runtime::time::wheel::level_for (5,497,710 samples, 0.02%)core::option::Option<T>::is_some (5,154,163 samples, 0.02%)tokio::sync::notify::Notified::poll_notified (17,440,916 samples, 0.07%)core::sync::atomic::AtomicUsize::compare_exchange (4,178,999 samples, 0.02%)core::sync::atomic::atomic_compare_exchange (4,178,999 samples, 0.02%)core::option::Option<T>::map (3,556,878 samples, 0.02%)tokio::time::sleep::Sleep::new_timeout (3,588,879 samples, 0.02%)tokio::runtime::scheduler::Handle::current (3,588,879 samples, 0.02%)tokio::runtime::context::current::with_current (3,588,879 samples, 0.02%)std::thread::local::LocalKey<T>::try_with (3,588,879 samples, 0.02%)tokio::runtime::context::current::with_current::_{{closure}} (3,588,879 samples, 0.02%)all (23,685,921,571 samples, 100%)tokio-runtime-w (23,655,059,228 samples, 99.87%)tokio-runtime-w \ No newline at end of file diff --git a/integration/go/dev.sh b/integration/go/dev.sh new file mode 100644 index 00000000..e13fe52c --- /dev/null +++ b/integration/go/dev.sh @@ -0,0 +1,8 @@ +#!/bin/bash +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +pushd ${SCRIPT_DIR} + +go get +go test -count 3 + +popd diff --git a/integration/go/go.mod b/integration/go/go.mod new file mode 100644 index 00000000..2b192319 --- /dev/null +++ b/integration/go/go.mod @@ -0,0 +1,17 @@ +module pg_tests + +go 1.24.3 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.4 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.10.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/text v0.21.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/integration/go/go.sum b/integration/go/go.sum new file mode 100644 index 00000000..3d77136e --- /dev/null +++ b/integration/go/go.sum @@ -0,0 +1,28 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg= +github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integration/go/pg_tests.go b/integration/go/pg_tests.go new file mode 100644 index 00000000..974236c7 --- /dev/null +++ b/integration/go/pg_tests.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("Run this test suite using 'go test'") +} diff --git a/integration/go/pg_tests_test.go b/integration/go/pg_tests_test.go new file mode 100644 index 00000000..5547df93 --- /dev/null +++ b/integration/go/pg_tests_test.go @@ -0,0 +1,129 @@ +package main + +import ( + "context" + "fmt" + "os" + "testing" + "time" + + "github.com/jackc/pgx/v5" + "github.com/stretchr/testify/assert" +) + +func assertNoOutOfSync(t *testing.T) { + conn, err := pgx.Connect(context.Background(), "postgres://admin:pgdog@127.0.0.1:6432/admin") + if err != nil { + panic(err) + } + defer conn.Close(context.Background()) + + rows, err := conn.Query(context.Background(), "SHOW POOLS", pgx.QueryExecModeSimpleProtocol) + defer rows.Close() + + for rows.Next() { + values, err := rows.Values() + if err != nil { + panic(err) + } + + out_of_sync := values[16].(int64) + assert.Equal(t, out_of_sync, int64(0), "No connections should be out of sync") + } +} + +func connectNormal() (*pgx.Conn, error) { + conn, err := pgx.Connect(context.Background(), "postgres://pgdog:pgdog@127.0.0.1:6432/pgdog") + if err != nil { + fmt.Fprintf(os.Stderr, "Can't connect: %v\n", err) + return nil, err + } + + return conn, nil +} + +func TestConnect(t *testing.T) { + conn, err := connectNormal() + if err != nil { + fmt.Fprintf(os.Stderr, "Can't connect: %v\n", err) + } + defer conn.Close(context.Background()) + + assertNoOutOfSync(t) + +} + +func TestSelect(t *testing.T) { + conn, err := connectNormal() + if err != nil { + panic(err) + } + defer conn.Close(context.Background()) + + for i := range 25 { + var one int64 + err = conn.QueryRow(context.Background(), "SELECT $1::bigint AS one", i).Scan(&one) + if err != nil { + panic(err) + } + assert.Equal(t, one, int64(i)) + } + +} + +func TestTimeout(t *testing.T) { + c := make(chan int, 1) + + // Using 9 because the pool size is 10 + // and we're executing a slow query that will block + // the pool for a while. + // Test pool size is 10. + for _ = range 9 { + go func() { + executeTimeoutTest(t) + c <- 1 + }() + } + + for _ = range 9 { + <-c + } + + // Wait for the conn to be drained and checked in + time.Sleep(2 * time.Second) + +} + +func executeTimeoutTest(t *testing.T) { + conn, err := connectNormal() + if err != nil { + panic(err) + } + defer conn.Close(context.Background()) + + ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) + defer cancel() + + c := make(chan int, 1) + + go func() { + err = pgSleepOneSecond(conn) + if err == nil { + panic(err) + } + + c <- 0 + }() + + select { + case <-c: + t.Error("Context should of been cancelled") + case <-ctx.Done(): + } +} + +// Sleep for 1 second. +func pgSleepOneSecond(conn *pgx.Conn) (err error) { + _, err = conn.Exec(context.Background(), "SELECT pg_sleep(1)") + return err +} diff --git a/integration/go/run.sh b/integration/go/run.sh new file mode 100644 index 00000000..83c730a2 --- /dev/null +++ b/integration/go/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +source ${SCRIPT_DIR}/../common.sh + +run_pgdog +wait_for_pgdog + +bash ${SCRIPT_DIR}/dev.sh + +stop_pgdog diff --git a/integration/load_balancer/docker-compose.yml b/integration/load_balancer/docker-compose.yml new file mode 100644 index 00000000..e6edcd63 --- /dev/null +++ b/integration/load_balancer/docker-compose.yml @@ -0,0 +1,25 @@ +services: + primary: + image: postgres:17 + environment: + POSTGRES_PASSWORD: postgres + volumes: + - ./docker/primary.sh:/docker-entrypoint-initdb.d/setup.sh + ports: + - 5433:5432 + replica_1: + image: postgres:17 + environment: + POSTGRES_PASSWORD: postgres + volumes: + - ./docker/replica.sh:/docker-entrypoint-initdb.d/setup.sh + ports: + - 5434:5432 + replica_2: + image: postgres:17 + environment: + POSTGRES_PASSWORD: postgres + volumes: + - ./docker/replica.sh:/docker-entrypoint-initdb.d/setup.sh + ports: + - 5435:5432 diff --git a/integration/load_balancer/docker/primary.sh b/integration/load_balancer/docker/primary.sh new file mode 100755 index 00000000..79d3ecd0 --- /dev/null +++ b/integration/load_balancer/docker/primary.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -e +DATA_DIR=/var/lib/postgresql/data + +# Enable replication connection +echo "host replication all all scram-sha-256" >> ${DATA_DIR}/pg_hba.conf +pg_ctl -D ${DATA_DIR} reload diff --git a/integration/load_balancer/docker/replica.sh b/integration/load_balancer/docker/replica.sh new file mode 100755 index 00000000..6cf8d2d8 --- /dev/null +++ b/integration/load_balancer/docker/replica.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -e +PRIMARY="primary" + +export PGHOST=${PRIMARY} +export PGPOST=5432 +export PGUSER=postgres +export PGPASSWORD=postgres +export PGDATABASE=postgres + +PRIMARY_CONN="postgres://postgres:postgres@${PRIMARY}:5432/postgres" +DATA_DIR="/var/lib/postgresql/data" +REPLICA_DIR="/var/lib/postgresql/replica" + +while ! pg_isready; do + sleep 1 +done + +echo "Removing old data directory" +pg_ctl -D ${DATA_DIR} stop +rm -f ${DATA_DIR}/postmaster.pid + +mkdir -p ${REPLICA_DIR} +chmod 750 ${REPLICA_DIR} + + +echo "Copying primary data directory" +pg_basebackup -D ${REPLICA_DIR} +touch ${REPLICA_DIR}/standby.signal + +echo "primary_conninfo = '${PRIMARY_CONN}'" >> ${REPLICA_DIR}/postgresql.auto.conf + +echo "Starting replica" +pg_ctl -D ${REPLICA_DIR} start || true +sleep infinity diff --git a/integration/load_balancer/pgdog.sh b/integration/load_balancer/pgdog.sh new file mode 100644 index 00000000..40044550 --- /dev/null +++ b/integration/load_balancer/pgdog.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e + +export PGUSER=postgres +export PGPORT=5434 +export PGHOST=127.0.0.1 +export PGDATABASE=postgres +export PGPASSWORD=postgres + +echo "Waiting for Postgres to be ready" +while ! pg_isready; do + sleep 1 +done + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +pushd ${SCRIPT_DIR}/../../ +cargo run -- --config ${SCRIPT_DIR}/pgdog.toml --users ${SCRIPT_DIR}/users.toml diff --git a/integration/load_balancer/pgdog.toml b/integration/load_balancer/pgdog.toml new file mode 100644 index 00000000..934d0752 --- /dev/null +++ b/integration/load_balancer/pgdog.toml @@ -0,0 +1,45 @@ +[general] +host = "0.0.0.0" +port = 6432 +shutdown_timeout = 5_000 +openmetrics_port = 9930 +query_timeout = 1_000 +checkout_timeout = 1_000 +connect_timeout = 1_000 +idle_timeout = 30_000 +prepared_statements = "extended" +passthrough_auth = "enabled_plain" +default_pool_size = 100 +workers = 10 +min_pool_size = 1 +pooler_mode = "transaction" +load_balancing_strategy = "least_active_connections" +auth_type = "trust" + +[admin] +user = "pgdog" +password = "pgdog" + +[[databases]] +name = "postgres" +host = "localhost" +port = 5435 +role = "replica" + +[[databases]] +name = "postgres" +host = "localhost" +role = "replica" +port = 5434 + +[[databases]] +name = "postgres" +host = "localhost" +role = "primary" +port = 5433 + +[tcp] +retries = 3 +time = 1000 +interval = 1000 +user_timeout = 1000 diff --git a/integration/load_balancer/requirements.txt b/integration/load_balancer/requirements.txt new file mode 100644 index 00000000..e5522575 --- /dev/null +++ b/integration/load_balancer/requirements.txt @@ -0,0 +1,20 @@ +asgiref==3.8.1 +asyncio==3.4.3 +asyncpg==0.30.0 +black==25.1.0 +click==8.2.0 +Django==5.1.7 +greenlet==3.1.1 +iniconfig==2.1.0 +mypy_extensions==1.1.0 +packaging==24.2 +pathspec==0.12.1 +platformdirs==4.3.8 +pluggy==1.5.0 +psycopg==3.2.6 +psycopg2==2.9.10 +pytest==8.3.5 +pytest-asyncio==0.26.0 +SQLAlchemy==2.0.39 +sqlparse==0.5.3 +typing_extensions==4.13.0 diff --git a/integration/load_balancer/test_lb_asyncpy.py b/integration/load_balancer/test_lb_asyncpy.py new file mode 100644 index 00000000..449cba83 --- /dev/null +++ b/integration/load_balancer/test_lb_asyncpy.py @@ -0,0 +1,82 @@ +import asyncpg +import pytest +import pytest_asyncio +from datetime import datetime +import json +from time import sleep +import random +import asyncio + +@pytest_asyncio.fixture +async def conn(): + conn = await asyncpg.connect("postgres://postgres:postgres@127.0.0.1:6432/postgres") + yield conn + await conn.close() + + +@pytest.mark.asyncio +async def test_connect(conn): + for _ in range(25): + result = await conn.fetch("SELECT 1::integer") + assert result[0][0] == 1 + +@pytest.mark.asyncio +async def test_prepared_statements(conn): + async with conn.transaction(): + await conn.execute("CREATE TABLE IF NOT EXISTS users (id BIGINT, email VARCHAR, created_at TIMESTAMPTZ, data JSONB)") + result = await conn.fetch(""" + INSERT INTO users (id, email, created_at, data) + VALUES ($1, $2, $3, $4), ($1, $2, $3, $4) RETURNING * + """, 1, "test@test.com", datetime.now(), json.dumps({"banned": False})) + + assert len(result) == 2 + for row in result: + assert row[0] == 1 + assert row[1] == "test@test.com" + assert row[3] == json.dumps({"banned": False}) + + for _ in range(3): + try: + row = await conn.fetch("SELECT * FROM users WHERE id = $1", 1) + assert row[0][1] == "test@test.com" + break + except: + # Replica lag + sleep(1) + +@pytest.mark.asyncio +async def test_concurrent(): + pool = await asyncpg.create_pool("postgres://postgres:postgres@127.0.0.1:6432/postgres") + tasks = [] + for _ in range(25): + task = asyncio.create_task(concurrent(pool)) + tasks.append(task) + for task in tasks: + await task + +async def concurrent(pool): + for _ in range(25): + async with pool.acquire() as conn: + i = random.randint(1, 1_000_000_000) + row = await conn.fetch("INSERT INTO users (id, created_at) VALUES ($1, NOW()) RETURNING id", i) + assert row[0][0] == i + + # Read from primary + async with pool.acquire() as conn: + async with conn.transaction(): + row = await conn.fetch("SELECT * FROM users WHERE id = $1", i) + assert row[0][0] == i + + async with pool.acquire() as conn: + # Try read from replica + for _ in range(3): + try: + row = await conn.fetch("SELECT * FROM users WHERE id = $1", i) + assert row[0][0] == i + break + except Exception as e: + assert "list index out of range" in str(e) + sleep(1) + + async with pool.acquire() as conn: + await conn.execute("DELETE FROM users WHERE id = $1", i) diff --git a/integration/load_balancer/users.toml b/integration/load_balancer/users.toml new file mode 100644 index 00000000..6a754682 --- /dev/null +++ b/integration/load_balancer/users.toml @@ -0,0 +1,4 @@ +[[users]] +name = "postgres" +database = "postgres" +password = "postgres" diff --git a/integration/pgbench/dev.sh b/integration/pgbench/dev.sh index cc9efaa2..1e408b25 100644 --- a/integration/pgbench/dev.sh +++ b/integration/pgbench/dev.sh @@ -1,6 +1,6 @@ #!/bin/bash SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) - +# set -e export PGPASSWORD=pgdog pgbench -i -h 127.0.0.1 -U pgdog -p 6432 pgdog diff --git a/integration/pgdog.toml b/integration/pgdog.toml index 99f5717d..dcd7cdac 100644 --- a/integration/pgdog.toml +++ b/integration/pgdog.toml @@ -3,11 +3,19 @@ query_timeout = 1_000 checkout_timeout = 1_000 connect_timeout = 1_000 load_balancing_strategy = "round_robin" +rollback_timeout = 1_000 +read_write_strategy = "aggressive" [[databases]] name = "pgdog" host = "127.0.0.1" +[[databases]] +name = "pgdog" +host = "127.0.0.1" +role = "replica" +read_only = true + [[databases]] name = "pgdog_sharded" host = "127.0.0.1" @@ -33,6 +41,7 @@ host = "127.0.0.1" port = 5436 role = "replica" database_name = "pgdog" +read_only = true [[databases]] name = "failover" @@ -40,6 +49,7 @@ host = "127.0.0.1" port = 5437 role = "replica" database_name = "pgdog" +read_only = true [[databases]] name = "failover" @@ -47,6 +57,7 @@ host = "127.0.0.1" port = 5438 role = "replica" database_name = "pgdog" +read_only = true [[sharded_tables]] database = "pgdog_sharded" @@ -57,9 +68,7 @@ primary = true [[omnisharded_tables]] database = "pgdog_sharded" -tables = [ - "sharded_omni" -] +tables = ["sharded_omni"] [admin] password = "pgdog" diff --git a/integration/python/dev.sh b/integration/python/dev.sh index 77d1b849..f60804d8 100644 --- a/integration/python/dev.sh +++ b/integration/python/dev.sh @@ -7,6 +7,6 @@ virtualenv venv source venv/bin/activate pip install -r requirements.txt -pytest +pytest -x popd diff --git a/integration/python/requirements.txt b/integration/python/requirements.txt index 27561235..e5522575 100644 --- a/integration/python/requirements.txt +++ b/integration/python/requirements.txt @@ -2,26 +2,19 @@ asgiref==3.8.1 asyncio==3.4.3 asyncpg==0.30.0 black==25.1.0 -certifi==2025.1.31 -charset-normalizer==3.4.1 -click==8.1.8 +click==8.2.0 Django==5.1.7 -execnet==2.1.1 greenlet==3.1.1 -idna==3.10 iniconfig==2.1.0 -mypy-extensions==1.0.0 +mypy_extensions==1.1.0 packaging==24.2 pathspec==0.12.1 -platformdirs==4.3.7 +platformdirs==4.3.8 pluggy==1.5.0 psycopg==3.2.6 psycopg2==2.9.10 pytest==8.3.5 pytest-asyncio==0.26.0 -pytest-xdist==3.6.1 -requests==2.32.3 SQLAlchemy==2.0.39 sqlparse==0.5.3 typing_extensions==4.13.0 -urllib3==2.4.0 diff --git a/integration/python/test_asyncpg.py b/integration/python/test_asyncpg.py index 3173fdd0..a8661beb 100644 --- a/integration/python/test_asyncpg.py +++ b/integration/python/test_asyncpg.py @@ -1,7 +1,7 @@ import asyncpg import pytest from datetime import datetime -from globals import normal_async, sharded_async, no_out_of_sync +from globals import normal_async, sharded_async, no_out_of_sync, admin import random import string import pytest_asyncio @@ -18,6 +18,9 @@ async def conns(): yield conns + admin_conn = admin() + admin_conn.execute("RECONNECT") # Remove lock on schema + for conn in conns: await conn.execute(f'DROP SCHEMA "{schema}" CASCADE') @@ -230,3 +233,38 @@ async def test_execute_many(conns): "INSERT INTO sharded (id, value) VALUES ($1, $2) RETURNING *", values ) assert len(rows) == 50 + +@pytest.mark.asyncio +async def test_stress(): + for i in range(100): + # Reconnect + normal = await normal_async() + await normal.execute("SET search_path TO '$user', public") + num = random.randint(1, 1_000_000) + # assert not await in_transaction(normal) + await normal.execute("DROP TABLE IF EXISTS test_stress") + # await not_in_transaction(normal) + await normal.execute("CREATE TABLE test_stress (id BIGINT)") + # await not_in_transaction(normal) + result = await normal.fetch("INSERT INTO test_stress VALUES ($1) RETURNING *", num) + assert result[0][0] == num + + # await not_in_transaction(normal) + result = await normal.fetch("SELECT * FROM test_stress WHERE id = $1", num) + assert result[0][0] == num + + # await not_in_transaction(normal) + await normal.fetch("TRUNCATE test_stress") + + # await not_in_transaction(normal) + assert (await normal.fetch("SELECT COUNT(*) FROM test_stress"))[0][0] == 0 + + for i in range(50): + await normal.execute("SELECT 1") + + # await not_in_transaction(normal) + await normal.execute("DROP TABLE test_stress") + + +async def in_transaction(conn): + await conn.fetch("SELECT now() != statement_timestamp()") diff --git a/integration/python/test_sqlalchemy.py b/integration/python/test_sqlalchemy.py index afb96514..545f18e8 100644 --- a/integration/python/test_sqlalchemy.py +++ b/integration/python/test_sqlalchemy.py @@ -2,6 +2,7 @@ from sqlalchemy.ext.asyncio import AsyncAttrs from sqlalchemy.ext.asyncio import async_sessionmaker from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.exc import IntegrityError, DBAPIError from sqlalchemy import select, text from sqlalchemy.orm import DeclarativeBase from sqlalchemy.orm import Mapped @@ -22,6 +23,13 @@ class Sharded(Base): value: Mapped[str] +class User(Base): + __tablename__ = "users" + + id: Mapped[int] = mapped_column(primary_key=True) + email: Mapped[str] + + @pytest_asyncio.fixture async def engines(): normal = create_async_engine( @@ -63,3 +71,91 @@ async def test_session_manager(engines): result = await session.execute(stmt) rows = result.fetchall() assert len(rows) == 1 + + +@pytest.mark.asyncio +async def test_with_errors(engines): + for engine in engines: + async with engine() as session: + await session.execute(text("DROP TABLE IF EXISTS sharded")) + await session.execute( + text("CREATE TABLE sharded (id BIGINT PRIMARY KEY, value VARCHAR)") + ) + await session.commit() + + async with engine() as session: + try: + session.add_all( + [ + Sharded(id=1, value="test"), + Sharded(id=1, value="test"), # duplicate key constraint + ] + ) + await session.commit() + except IntegrityError as e: + assert ( + 'duplicate key value violates unique constraint "sharded_pkey"' + in str(e) + ) + await session.rollback() + + session.add_all([Sharded(id=3, value="test")]) + await session.commit() + for engine in engines: + async with engine() as session: + session.add(Sharded(id=5, value="random")) + await session.commit() + session.add(Sharded(id=6, value="random")) + result = await session.execute(select(Sharded).where(Sharded.id == 6)) + rows = result.fetchall() + assert len(rows) == 1 + + +@pytest.mark.asyncio +async def test_reads_writes(engines): + normal = engines[0] # Not sharded + reads = set() + + for i in range(50): + email = f"test-{i}@test.com" + async with normal() as session: + await session.execute(text("DROP TABLE IF EXISTS users")) + await session.execute( + text("CREATE TABLE users (id BIGSERIAL PRIMARY KEY, email VARCHAR)") + ) + await session.commit() + async with normal() as session: + session.add(User(email=email)) + await session.commit() + async with normal() as session: + await session.begin() + stmt = select(User).filter(User.email == email) + user = await session.execute(stmt) + user = user.scalar_one_or_none() + assert user.email == email + result = await session.execute(text("SHOW default_transaction_read_only")) + rows = result.fetchone() + reads.add(rows[0]) + await session.commit() + assert len(reads) == 2 + + +@pytest.mark.asyncio +async def test_write_in_read(engines): + normal = engines[0] + + for i in range(50): + async with normal() as session: + # Setup + await session.execute(text("DROP TABLE IF EXISTS test_read_write")) + await session.execute(text("CREATE TABLE test_read_write (id BIGINT)")) + await session.commit() + # Trigger PgDog to route this to a replica with a read + await session.begin() + await session.execute(text("SELECT * FROM test_read_write")) + try: + # This is still inside the same transaction. The entire transaction + # is going to a replica right now. + await session.execute(text("INSERT INTO test_read_write VALUES (1)")) + except DBAPIError as e: + assert "cannot execute INSERT in a read-only transaction" in str(e) diff --git a/integration/rust/dev.sh b/integration/rust/dev.sh index 796f581a..400895fb 100644 --- a/integration/rust/dev.sh +++ b/integration/rust/dev.sh @@ -3,5 +3,5 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) set -e pushd ${SCRIPT_DIR} -cargo nextest run --no-fail-fast +cargo nextest run --no-fail-fast --test-threads=1 popd diff --git a/integration/rust/src/setup.rs b/integration/rust/src/setup.rs index 6c4b865f..2fa02b99 100644 --- a/integration/rust/src/setup.rs +++ b/integration/rust/src/setup.rs @@ -73,20 +73,16 @@ pub async fn backends(application_name: &str, pool: &Pool) -> Vec Pool { - let pool = PgPoolOptions::new() + PgPoolOptions::new() .max_connections(5) - .connect(&format!( - "postgres://pgdog:pgdog@127.0.0.1:6432/failover?application_name=sqlx" - )) + .connect("postgres://pgdog:pgdog@127.0.0.1:6432/failover?application_name=sqlx") .await - .unwrap(); - - pool + .unwrap() } pub async fn admin_tokio() -> Client { let (client, connection) = tokio_postgres::connect( - &format!("host=127.0.0.1 user=admin dbname=admin password=pgdog port=6432",), + "host=127.0.0.1 user=admin dbname=admin password=pgdog port=6432", NoTls, ) .await @@ -102,11 +98,9 @@ pub async fn admin_tokio() -> Client { } pub async fn admin_sqlx() -> Pool { - let pool = PgPoolOptions::new() + PgPoolOptions::new() .max_connections(1) - .connect(&format!("postgres://admin:pgdog@127.0.0.1:6432/admin")) + .connect("postgres://admin:pgdog@127.0.0.1:6432/admin") .await - .unwrap(); - - pool + .unwrap() } diff --git a/integration/rust/tests/integration/auth.rs b/integration/rust/tests/integration/auth.rs new file mode 100644 index 00000000..02f86f19 --- /dev/null +++ b/integration/rust/tests/integration/auth.rs @@ -0,0 +1,43 @@ +use rust::setup::admin_sqlx; +use serial_test::serial; +use sqlx::{Connection, Executor, PgConnection, Row}; + +#[tokio::test] +#[serial] +async fn test_auth() { + let admin = admin_sqlx().await; + let bad_password = "postgres://pgdog:skjfhjk23h4234@127.0.0.1:6432/pgdog"; + + admin.execute("SET auth_type TO 'trust'").await.unwrap(); + assert_auth("trust").await; + + let mut any_password = PgConnection::connect(bad_password).await.unwrap(); + any_password.execute("SELECT 1").await.unwrap(); + + let mut empty_password = PgConnection::connect("postgres://pgdog@127.0.0.1:6432/pgdog") + .await + .unwrap(); + empty_password.execute("SELECT 1").await.unwrap(); + + admin.execute("SET auth_type TO 'scram'").await.unwrap(); + assert_auth("scram").await; + + assert!(PgConnection::connect(bad_password).await.is_err()); +} + +async fn assert_auth(expected: &str) { + let admin = admin_sqlx().await; + let rows = admin.fetch_all("SHOW CONFIG").await.unwrap(); + let mut found = false; + for row in rows { + let name: String = row.get(0); + let value: String = row.get(1); + + if name == "auth_type" { + found = true; + assert_eq!(value, expected); + } + } + + assert!(found); +} diff --git a/integration/rust/tests/integration/fake_transactions.rs b/integration/rust/tests/integration/fake_transactions.rs index a2caf038..c6ed1e4c 100644 --- a/integration/rust/tests/integration/fake_transactions.rs +++ b/integration/rust/tests/integration/fake_transactions.rs @@ -5,21 +5,50 @@ use sqlx::{Executor, Pool, Postgres, Row}; #[tokio::test] #[serial] async fn test_fake_transactions() { - let conn = connections_sqlx().await.into_iter().skip(1).next().unwrap(); + let conn = connections_sqlx().await.into_iter().nth(1).unwrap(); let admin = admin_sqlx().await; + admin + .execute("SET read_write_strategy TO 'conservative'") + .await + .unwrap(); + + for _ in 0..5 { + conn.execute("SET application_name TO 'test_fake_transactions'") + .await + .unwrap(); + conn.execute("BEGIN").await.unwrap(); + check_client_state("idle in transaction", admin.clone()).await; + assert!(check_server_state("idle in transaction", admin.clone()).await); + conn.execute("ROLLBACK").await.unwrap(); + check_client_state("idle", admin.clone()).await; + assert!(check_server_state("idle", admin.clone()).await); + } + + admin + .execute("SET read_write_strategy TO 'aggressive'") + .await + .unwrap(); + for _ in 0..5 { conn.execute("SET application_name TO 'test_fake_transactions'") .await .unwrap(); conn.execute("BEGIN").await.unwrap(); - check_state("idle in transaction", admin.clone()).await; + check_client_state("idle in transaction", admin.clone()).await; + assert!(check_server_state("idle", admin.clone()).await); + conn.execute("CREATE TABLE test_fake_transactions (id BIGINT)") + .await + .unwrap(); + check_client_state("idle in transaction", admin.clone()).await; + assert!(check_server_state("idle in transaction", admin.clone()).await); conn.execute("ROLLBACK").await.unwrap(); - check_state("idle", admin.clone()).await; + check_client_state("idle", admin.clone()).await; + assert!(check_server_state("idle", admin.clone()).await); } } -async fn check_state(expected: &str, admin: Pool) { +async fn check_client_state(expected: &str, admin: Pool) { let clients = admin.fetch_all("SHOW CLIENTS").await.unwrap(); let mut ok = false; @@ -36,3 +65,20 @@ async fn check_state(expected: &str, admin: Pool) { assert!(ok); } + +async fn check_server_state(expected: &str, admin: Pool) -> bool { + let clients = admin.fetch_all("SHOW SERVERS").await.unwrap(); + let mut ok = false; + + for client in clients { + let state: String = client.get("state"); + let database: String = client.get("database"); + let application_name: String = client.get("application_name"); + + if database.starts_with("shard_") && application_name == "test_fake_transactions" { + ok = state == expected; + } + } + + ok +} diff --git a/integration/rust/tests/integration/mod.rs b/integration/rust/tests/integration/mod.rs index b27f7b77..31818dfd 100644 --- a/integration/rust/tests/integration/mod.rs +++ b/integration/rust/tests/integration/mod.rs @@ -1,3 +1,4 @@ +pub mod auth; pub mod fake_transactions; pub mod reload; pub mod syntax_error; diff --git a/integration/rust/tests/integration/reload.rs b/integration/rust/tests/integration/reload.rs index 9382d1ec..62b70bc0 100644 --- a/integration/rust/tests/integration/reload.rs +++ b/integration/rust/tests/integration/reload.rs @@ -42,6 +42,7 @@ async fn test_reconnect() { conn.execute("SET application_name TO 'test_reconnect'") .await .unwrap(); + conn.execute("SELECT 1").await.unwrap(); // Trigger param update. let backends_before = backends("test_reconnect", &conn).await; diff --git a/integration/rust/tests/sqlx/bad_auth.rs b/integration/rust/tests/sqlx/bad_auth.rs index f364211d..35328f42 100644 --- a/integration/rust/tests/sqlx/bad_auth.rs +++ b/integration/rust/tests/sqlx/bad_auth.rs @@ -1,6 +1,8 @@ +use serial_test::serial; use sqlx::{Connection, PgConnection}; #[tokio::test] +#[serial] async fn test_bad_auth() { for user in ["pgdog", "pgdog_bad_user"] { for password in ["bad_password", "another_password", ""] { diff --git a/integration/setup.sh b/integration/setup.sh index 848e4a5a..133d8cd9 100644 --- a/integration/setup.sh +++ b/integration/setup.sh @@ -21,6 +21,7 @@ fi export PGPASSWORD='pgdog' export PGHOST=127.0.0.1 export PGPORT=5432 +#export PGUSER='pgdog' for db in pgdog shard_0 shard_1; do psql -c "CREATE DATABASE $db" || true @@ -40,8 +41,6 @@ done pushd ${SCRIPT_DIR} -set -e - for bin in toxiproxy-server toxiproxy-cli; do if [[ ! -f ${bin} ]]; then curl -L https://github.com/Shopify/toxiproxy/releases/download/v2.12.0/${bin}-${OS}-${ARCH} > ${bin} diff --git a/integration/toxi/dev.sh b/integration/toxi/dev.sh index e4479112..ada68fef 100644 --- a/integration/toxi/dev.sh +++ b/integration/toxi/dev.sh @@ -3,13 +3,7 @@ set -e SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) export GEM_HOME=~/.gem -if [[ ! -z "$1" ]]; then - E="-e ${1}" -else - E="" -fi - pushd ${SCRIPT_DIR} bundle install -bundle exec rspec *_spec.rb -fd ${E} +bundle exec rspec *_spec.rb -fd --fail-fast popd diff --git a/integration/toxi/rspec_helper.rb b/integration/toxi/rspec_helper.rb index a308ce49..79615fe6 100644 --- a/integration/toxi/rspec_helper.rb +++ b/integration/toxi/rspec_helper.rb @@ -4,6 +4,7 @@ require 'pg' require 'concurrent' require 'active_record' +require 'timeout' def conn PG.connect 'postgres://pgdog:pgdog@127.0.0.1:6432/failover' diff --git a/integration/toxi/toxi_spec.rb b/integration/toxi/toxi_spec.rb index c59d3675..0588a77d 100644 --- a/integration/toxi/toxi_spec.rb +++ b/integration/toxi/toxi_spec.rb @@ -92,6 +92,12 @@ def warm_up end describe 'tcp' do + around :each do |example| + Timeout.timeout(10) do + example.run + end + end + it 'can connect' do c = conn tup = c.exec 'SELECT 1::bigint AS one' diff --git a/pgdog.toml b/pgdog.toml index c5203b06..f9bb749a 100644 --- a/pgdog.toml +++ b/pgdog.toml @@ -1,18 +1,13 @@ # -# minimal pgDog configuration for a single user, single -# primary database running on the same host. +# PgDog configuration. # [general] host = "0.0.0.0" port = 6432 shutdown_timeout = 5_000 openmetrics_port = 9090 -query_timeout = 1_000 -checkout_timeout = 1_000 -connect_timeout = 1_000 -passthrough_auth = "enabled_plain" -idle_timeout = 30_000 -# dry_run = true +idle_healthcheck_delay = 2342343243 +read_write_strategy = "aggressive" # # Admin database password. @@ -34,16 +29,7 @@ name = "pgdog" host = "127.0.0.1" port = 5432 role = "replica" - -[[databases]] -name = "mastodon_development" -host = "127.0.0.1" -role = "primary" - -[[databases]] -name = "mastodon_development" -host = "127.0.0.1" -role = "replica" +read_only = true [tcp] retries = 3 @@ -60,26 +46,28 @@ name = "pgdog_sharded" host = "127.0.0.1" database_name = "shard_0" shard = 0 +role = "primary" [[databases]] name = "pgdog_sharded" host = "127.0.0.1" database_name = "shard_1" shard = 1 +role = "primary" [[databases]] -name = "failover" +name = "pgdog_sharded" host = "127.0.0.1" -port = 5435 -role = "primary" -database_name = "pgdog" +database_name = "shard_0" +shard = 0 +role = "replica" [[databases]] -name = "failover" +name = "pgdog_sharded" host = "127.0.0.1" -port = 5436 +database_name = "shard_1" +shard = 1 role = "replica" -database_name = "pgdog" # # Read/write access to theses tables will be automatically @@ -92,68 +80,6 @@ column = "id" data_type = "bigint" primary = true -[[sharded_tables]] -database = "pgdog_sharded" -name = "users" -data_type = "bigint" -column = "id" -primary = true - -[[omnisharded_tables]] -database = "pgdog_sharded" -tables = [ - "sharded_omni" -] - -[[sharded_tables]] -database = "pgdog_sharded" -name = "embeddings" -data_type = "vector" -column = "embedding" -centroids_path = "examples/pgvector/centroids.json" - -[[sharded_tables]] -database = "mastodon_development" -data_type = "bigint" -column = "account_id" - -[[sharded_tables]] -database = "mastodon_development" -data_type = "bigint" -name = "accounts" -column = "id" - -[[sharded_tables]] -database = "mastodon_development" -column = "remote_account_id" - -[[sharded_tables]] -database = "mastodon_development" -column = "target_account_id" - -[[sharded_tables]] -database = "mastodon_development" -column = "reference_account_id" - -[[sharded_tables]] -database = "mastodon_development" -column = "from_account_id" - -[[sharded_tables]] -database = "mastodon_development" -column = "action_taken_by_account_id" - -[[omnisharded_tables]] -database = "mastodon_development" -tables = [ - "settings", - "settings", - "site_uploads", - "ip_blocks", - "terms_of_services", - "account_statuses_cleanup_policies", -] - # # ActiveRecord sends these queries @@ -179,3 +105,9 @@ fingerprint = "bb38525ebeb46656" #[13490623250668217942] [[manual_query]] fingerprint = "f4814b6fadabc4c1" #[17618446160277259457] + +[[manual_query]] +fingerprint = "04dc05f480b702d3" + +[multi_tenant] +column = "tenant_id" diff --git a/pgdog/Cargo.lock b/pgdog/Cargo.lock new file mode 100644 index 00000000..35650a35 --- /dev/null +++ b/pgdog/Cargo.lock @@ -0,0 +1,1183 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "aws-lc-rs" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f409eb70b561706bf8abba8ca9c112729c481595893fd06a2dd9af8ed8441148" +dependencies = [ + "aws-lc-sys", + "paste", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923ded50f602b3007e5e63e3f094c479d9c8a9b42d7f4034e4afe456aa48bfd2" +dependencies = [ + "bindgen", + "cc", + "cmake", + "dunce", + "fs_extra", + "paste", +] + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", + "which", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" + +[[package]] +name = "cc" +version = "1.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "cmake" +version = "0.1.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" +dependencies = [ + "cc", +] + +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "indexmap" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pgdog" +version = "0.1.0" +dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "once_cell", + "parking_lot", + "pin-project", + "rand", + "rustls-native-certs", + "rustls-pki-types", + "serde", + "thiserror", + "tokio", + "tokio-rustls", + "toml", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "pin-project" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.23.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81d3f8c9bfcc3cbb6b0179eb57042d75b1582bdc65c3cb95f3fa999509c03cbc" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tokio" +version = "1.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" +dependencies = [ + "memchr", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/pgdog/Cargo.toml b/pgdog/Cargo.toml index ed71ad33..d0009913 100644 --- a/pgdog/Cargo.toml +++ b/pgdog/Cargo.toml @@ -13,6 +13,7 @@ readme = "README.md" tui = ["ratatui"] # default = ["tui"] + [dependencies] pin-project = "1" tokio = { version = "1", features = ["full"] } diff --git a/pgdog/src/admin/backend.rs b/pgdog/src/admin/backend.rs index b7c88148..6b725f48 100644 --- a/pgdog/src/admin/backend.rs +++ b/pgdog/src/admin/backend.rs @@ -7,6 +7,7 @@ use tokio::time::sleep; use tracing::debug; use crate::backend::ProtocolMessage; +use crate::frontend::Buffer; use crate::net::messages::command_complete::CommandComplete; use crate::net::messages::{ErrorResponse, FromBytes, Protocol, Query, ReadyForQuery}; use crate::net::ToBytes; @@ -36,12 +37,9 @@ impl Backend { } /// Handle command. - pub async fn send( - &mut self, - messages: Vec + Clone>, - ) -> Result<(), Error> { + pub async fn send(&mut self, messages: &Buffer) -> Result<(), Error> { let message = messages.first().ok_or(Error::Empty)?; - let message: ProtocolMessage = message.clone().into(); + let message: ProtocolMessage = message.clone(); if message.code() != 'Q' { debug!("admin received unsupported message: {:?}", message); @@ -53,12 +51,7 @@ impl Backend { let messages = match Parser::parse(&query.query().to_lowercase()) { Ok(command) => { let mut messages = command.execute().await?; - messages.push( - CommandComplete { - command: command.name(), - } - .message()?, - ); + messages.push(CommandComplete::new(command.name()).message()?); messages } diff --git a/pgdog/src/admin/error.rs b/pgdog/src/admin/error.rs index 984a8574..677e9830 100644 --- a/pgdog/src/admin/error.rs +++ b/pgdog/src/admin/error.rs @@ -21,4 +21,10 @@ pub enum Error { #[error("{0}")] Backend(Box), + + #[error("parse int")] + ParseInt(#[from] std::num::ParseIntError), + + #[error("{0}")] + Config(#[from] crate::config::error::Error), } diff --git a/pgdog/src/admin/parser.rs b/pgdog/src/admin/parser.rs index 41ad9f08..36549a64 100644 --- a/pgdog/src/admin/parser.rs +++ b/pgdog/src/admin/parser.rs @@ -131,7 +131,7 @@ impl Parser { // TODO: This is not ready yet. We have a race and // also the changed settings need to be propagated // into the pools. - // "set" => ParseResult::Set(Set::parse(&sql)?), + "set" => ParseResult::Set(Set::parse(&sql)?), command => { debug!("unknown admin command: {}", command); return Err(Error::Syntax); diff --git a/pgdog/src/admin/reload.rs b/pgdog/src/admin/reload.rs index 0463ceae..fd6e687d 100644 --- a/pgdog/src/admin/reload.rs +++ b/pgdog/src/admin/reload.rs @@ -1,7 +1,7 @@ //! RELOAD command. use super::prelude::*; -use crate::databases::reload; +use crate::backend::databases::reload; pub struct Reload; diff --git a/pgdog/src/admin/set.rs b/pgdog/src/admin/set.rs index 897b971c..c73617a5 100644 --- a/pgdog/src/admin/set.rs +++ b/pgdog/src/admin/set.rs @@ -1,11 +1,14 @@ -use crate::config::config; +use crate::{ + backend::databases, + config::{self, config}, +}; use super::prelude::*; use pg_query::{parse, protobuf::a_const, NodeEnum}; pub struct Set { name: String, - value: u64, + value: String, } #[async_trait] @@ -26,17 +29,20 @@ impl Command for Set { let node = setting.node.clone().ok_or(Error::Syntax)?; match node { NodeEnum::AConst(a_const) => match a_const.val { - Some(a_const::Val::Ival(val)) => { - return Ok(Self { - name, - value: val.ival as u64, - }); - } - - _ => return Err(Error::Syntax), + Some(a_const::Val::Ival(val)) => Ok(Self { + name, + value: val.ival.to_string(), + }), + + Some(a_const::Val::Sval(sval)) => Ok(Self { + name, + value: sval.sval.to_string(), + }), + + _ => Err(Error::Syntax), }, - _ => return Err(Error::Syntax), + _ => Err(Error::Syntax), } } @@ -45,19 +51,33 @@ impl Command for Set { } async fn execute(&self) -> Result, Error> { - let mut general = config().config.general.clone(); + let _lock = databases::lock(); + let mut config = (*config()).clone(); match self.name.as_str() { "query_timeout" => { - general.query_timeout = self.value; + config.config.general.query_timeout = self.value.parse()?; } "checkout_timeout" => { - general.checkout_timeout = self.value; + config.config.general.checkout_timeout = self.value.parse()?; + } + + "auth_type" => { + config.config.general.auth_type = + serde_json::from_str(&format!(r#""{}""#, self.value))?; + } + + "read_write_strategy" => { + config.config.general.read_write_strategy = + serde_json::from_str(&format!(r#""{}""#, self.value))?; } _ => return Err(Error::Syntax), } + config::set(config)?; + databases::init(); + Ok(vec![]) } } @@ -71,6 +91,6 @@ mod test { let cmd = "SET query_timeout TO 5000"; let cmd = Set::parse(cmd).unwrap(); assert_eq!(cmd.name, "query_timeout"); - assert_eq!(cmd.value, 5000); + assert_eq!(cmd.value, "5000"); } } diff --git a/pgdog/src/admin/show_clients.rs b/pgdog/src/admin/show_clients.rs index b12278da..12076332 100644 --- a/pgdog/src/admin/show_clients.rs +++ b/pgdog/src/admin/show_clients.rs @@ -39,6 +39,7 @@ impl Command for ShowClients { Field::numeric("bytes_sent"), Field::numeric("errors"), Field::text("application_name"), + Field::numeric("memory_used"), ]); let mut rows = vec![]; @@ -73,7 +74,8 @@ impl Command for ShowClients { .add(client.stats.bytes_received) .add(client.stats.bytes_sent) .add(client.stats.errors) - .add(client.paramters.get_default("application_name", "")); + .add(client.paramters.get_default("application_name", "")) + .add(client.stats.memory_used); rows.push(row.message()?); } diff --git a/pgdog/src/admin/show_config.rs b/pgdog/src/admin/show_config.rs index 17803e14..fc969de4 100644 --- a/pgdog/src/admin/show_config.rs +++ b/pgdog/src/admin/show_config.rs @@ -32,7 +32,7 @@ impl Command for ShowConfig { // Reflection using JSON. let general = serde_json::to_value(&config.config.general)?; - let tcp = serde_json::to_value(&config.config.tcp)?; + let tcp = serde_json::to_value(config.config.tcp)?; let objects = [("", general.as_object()), ("tcp_", tcp.as_object())]; for (prefix, object) in objects.iter() { diff --git a/pgdog/src/admin/show_pools.rs b/pgdog/src/admin/show_pools.rs index 4fd5d17d..b0b154df 100644 --- a/pgdog/src/admin/show_pools.rs +++ b/pgdog/src/admin/show_pools.rs @@ -36,6 +36,7 @@ impl Command for ShowPools { Field::bool("paused"), Field::bool("banned"), Field::numeric("errors"), + Field::numeric("re_synced"), Field::numeric("out_of_sync"), Field::bool("online"), ]); @@ -63,6 +64,7 @@ impl Command for ShowPools { .add(state.paused) .add(state.banned) .add(state.errors) + .add(state.re_synced) .add(state.out_of_sync) .add(state.online); messages.push(row.message()?); diff --git a/pgdog/src/admin/show_query_cache.rs b/pgdog/src/admin/show_query_cache.rs index e24a1898..3e74816c 100644 --- a/pgdog/src/admin/show_query_cache.rs +++ b/pgdog/src/admin/show_query_cache.rs @@ -36,7 +36,7 @@ impl Command for ShowQueryCache { ]) .message()?]; - let mut queries: Vec<_> = queries.into_iter().map(|(k, v)| (k, v)).collect(); + let mut queries: Vec<_> = queries.into_iter().collect(); queries.sort_by_key(|v| v.1.hits); for query in queries.into_iter().rev() { diff --git a/pgdog/src/admin/show_servers.rs b/pgdog/src/admin/show_servers.rs index 0d3ca7e4..bd07c6e2 100644 --- a/pgdog/src/admin/show_servers.rs +++ b/pgdog/src/admin/show_servers.rs @@ -1,6 +1,7 @@ //! SHOW SERVERS command. -use std::time::{Instant, SystemTime}; +use std::time::SystemTime; +use tokio::time::Instant; use crate::{ backend::stats::stats, @@ -42,6 +43,7 @@ impl Command for ShowServers { Field::numeric("bytes_received"), Field::numeric("bytes_sent"), Field::numeric("age"), + Field::text("application_name"), ]) .message()?]; @@ -70,7 +72,8 @@ impl Command for ShowServers { .add(server.stats.total.errors) .add(server.stats.total.bytes_received) .add(server.stats.total.bytes_sent) - .add(age.as_secs() as i64); + .add(age.as_secs() as i64) + .add(server.application_name.as_str()); messages.push(dr.message()?); } diff --git a/pgdog/src/admin/show_stats.rs b/pgdog/src/admin/show_stats.rs index 7217d205..713e5759 100644 --- a/pgdog/src/admin/show_stats.rs +++ b/pgdog/src/admin/show_stats.rs @@ -74,9 +74,9 @@ impl Command for ShowStats { .add(stat.server_assignment_count) .add(stat.received) .add(stat.sent) - .add(stat.xact_time) - .add(stat.query_time) - .add(stat.wait_time) + .add(stat.xact_time.as_millis() as u64) + .add(stat.query_time.as_millis() as u64) + .add(stat.wait_time.as_millis() as u64) // .add(0_i64) .add(stat.parse_count) .add(stat.bind_count); diff --git a/pgdog/src/auth/scram/server.rs b/pgdog/src/auth/scram/server.rs index 85176c46..3cb6a3a3 100644 --- a/pgdog/src/auth/scram/server.rs +++ b/pgdog/src/auth/scram/server.rs @@ -50,6 +50,7 @@ use base64::prelude::*; impl AuthenticationProvider for UserPassword { fn get_password_for(&self, _user: &str) -> Option { + // TODO: This is slow. We should move it to its own thread pool. let iterations = 4096; let salt = rand::thread_rng().gen::<[u8; 16]>().to_vec(); let hash = hash_password(&self.password, NonZeroU32::new(iterations).unwrap(), &salt); diff --git a/pgdog/src/backend/databases.rs b/pgdog/src/backend/databases.rs index 40c91a18..810edaeb 100644 --- a/pgdog/src/backend/databases.rs +++ b/pgdog/src/backend/databases.rs @@ -1,11 +1,14 @@ //! Databases behind pgDog. +use std::collections::BTreeSet; use std::collections::{hash_map::Entry, HashMap}; use std::sync::Arc; use arc_swap::ArcSwap; use once_cell::sync::Lazy; -use parking_lot::Mutex; +use parking_lot::lock_api::MutexGuard; +use parking_lot::{Mutex, RawMutex}; +use tracing::{info, warn}; use crate::{ backend::pool::PoolConfig, @@ -15,6 +18,7 @@ use crate::{ use super::{ pool::{Address, ClusterConfig, Config}, + reload_notify, replication::ReplicationConfig, Cluster, ClusterShardConfig, Error, ShardedTables, }; @@ -23,6 +27,11 @@ static DATABASES: Lazy> = Lazy::new(|| ArcSwap::from_pointee(Databases::default())); static LOCK: Lazy> = Lazy::new(|| Mutex::new(())); +/// Sync databases during modification. +pub fn lock() -> MutexGuard<'static, RawMutex, ()> { + LOCK.lock() +} + /// Get databases handle. /// /// This allows to access any database proxied by pgDog. @@ -36,6 +45,7 @@ pub fn replace_databases(new_databases: Databases, reload: bool) { // to ensure zero downtime for clients. let old_databases = databases(); let new_databases = Arc::new(new_databases); + reload_notify::started(); if reload { // Move whatever connections we can over to new pools. old_databases.move_conns_to(&new_databases); @@ -43,6 +53,7 @@ pub fn replace_databases(new_databases: Databases, reload: bool) { new_databases.launch(); DATABASES.store(new_databases); old_databases.shutdown(); + reload_notify::done(); } /// Re-create all connections. @@ -144,6 +155,7 @@ impl ToUser for (&str, Option<&str>) { pub struct Databases { databases: HashMap, manual_queries: HashMap, + mirrors: HashMap>, } impl Databases { @@ -184,6 +196,16 @@ impl Databases { } } + pub fn mirrors(&self, user: impl ToUser) -> Result, Error> { + let user = user.to_user(); + if let Some(cluster) = self.databases.get(&user) { + let name = cluster.name(); + Ok(self.mirrors.get(name).map(|m| m.as_slice())) + } else { + Err(Error::NoDatabase(user.clone())) + } + } + /// Get replication configuration for the database. pub fn replication(&self, database: &str) -> Option { for (user, cluster) in &self.databases { @@ -249,6 +271,7 @@ impl Databases { .map(|(k, v)| (k.clone(), v.duplicate())) .collect(), manual_queries: self.manual_queries.clone(), + mirrors: self.mirrors.clone(), } } @@ -261,8 +284,17 @@ impl Databases { /// Launch all pools. fn launch(&self) { - for cluster in self.all().values() { + let mirrors = self.all().values().filter(|c| c.mirror_of().is_some()); + let normal = self.all().values().filter(|c| c.mirror_of().is_none()); + for cluster in mirrors.chain(normal) { cluster.launch(); + if let Some(mirror_of) = cluster.mirror_of() { + info!( + r#"enabling mirroring of database "{}" into "{}""#, + mirror_of, + cluster.name(), + ); + } } } } @@ -276,6 +308,7 @@ pub(crate) fn new_pool( let general = &config.general; let databases = config.databases(); let shards = databases.get(&user.database); + let mut mirrors_of = BTreeSet::new(); if let Some(shards) = shards { let mut shard_configs = vec![]; @@ -283,16 +316,22 @@ pub(crate) fn new_pool( let primary = user_databases .iter() .find(|d| d.role == Role::Primary) - .map(|primary| PoolConfig { - address: Address::new(primary, user), - config: Config::new(general, primary, user), + .map(|primary| { + mirrors_of.insert(primary.mirror_of.clone()); + PoolConfig { + address: Address::new(primary, user), + config: Config::new(general, primary, user), + } }); let replicas = user_databases .iter() .filter(|d| d.role == Role::Replica) - .map(|replica| PoolConfig { - address: Address::new(replica, user), - config: Config::new(general, replica, user), + .map(|replica| { + mirrors_of.insert(replica.mirror_of.clone()); + PoolConfig { + address: Address::new(replica, user), + config: Config::new(general, replica, user), + } }) .collect::>(); @@ -309,7 +348,29 @@ pub(crate) fn new_pool( .unwrap_or(vec![]); let sharded_tables = ShardedTables::new(sharded_tables, omnisharded_tables, general.dry_run); - let cluster_config = ClusterConfig::new(general, user, &shard_configs, sharded_tables); + // Make sure all nodes in the cluster agree they are mirroring the same cluster. + let mirror_of = match mirrors_of.len() { + 0 => None, + 1 => mirrors_of + .first() + .and_then(|s| s.as_ref().map(|s| s.as_str())), + _ => { + warn!( + "database \"{}\" has different \"mirror_of\" settings, disabling mirroring", + user.database + ); + None + } + }; + + let cluster_config = ClusterConfig::new( + general, + user, + &shard_configs, + sharded_tables, + mirror_of, + config.multi_tenant(), + ); Some(( User { @@ -333,8 +394,21 @@ pub fn from_config(config: &ConfigAndUsers) -> Databases { } } + let mut mirrors = HashMap::new(); + + for cluster in databases.values() { + let mirror_clusters = databases + .iter() + .find(|(_, c)| c.mirror_of() == Some(cluster.name())) + .map(|(_, c)| c.clone()) + .into_iter() + .collect::>(); + mirrors.insert(cluster.name().to_owned(), mirror_clusters); + } + Databases { databases, manual_queries: config.config.manual_queries(), + mirrors, } } diff --git a/pgdog/src/backend/mod.rs b/pgdog/src/backend/mod.rs index a6aa1c66..371e7857 100644 --- a/pgdog/src/backend/mod.rs +++ b/pgdog/src/backend/mod.rs @@ -5,6 +5,7 @@ pub mod error; pub mod pool; pub mod prepared_statements; pub mod protocol; +pub mod reload_notify; pub mod replication; pub mod schema; pub mod server; diff --git a/pgdog/src/backend/pool/ban.rs b/pgdog/src/backend/pool/ban.rs index cf69e7ed..6a2cffc7 100644 --- a/pgdog/src/backend/pool/ban.rs +++ b/pgdog/src/backend/pool/ban.rs @@ -1,5 +1,6 @@ //! Pool ban. -use std::time::{Duration, Instant}; +use std::time::Duration; +use tokio::time::Instant; use super::Error; @@ -27,8 +28,8 @@ impl Ban { false } else { let duration = now.duration_since(self.created_at); - let expired = duration > self.ban_timeout; - expired + + duration > self.ban_timeout } } } diff --git a/pgdog/src/backend/pool/cleanup.rs b/pgdog/src/backend/pool/cleanup.rs index 36a3bbc8..365c0831 100644 --- a/pgdog/src/backend/pool/cleanup.rs +++ b/pgdog/src/backend/pool/cleanup.rs @@ -1,20 +1,52 @@ //! Cleanup queries for servers altered by client behavior. +use once_cell::sync::Lazy; + +use crate::net::Query; + use super::{super::Server, Guard}; +static PREPARED: Lazy> = Lazy::new(|| vec![Query::new("DEALLOCATE ALL")]); +static PARAMS: Lazy> = Lazy::new(|| vec![Query::new("DISCARD ALL")]); +static ALL: Lazy> = Lazy::new(|| { + vec!["DISCARD ALL", "DEALLOCATE ALL"] + .into_iter() + .map(Query::new) + .collect() +}); +static NONE: Lazy> = Lazy::new(Vec::new); + /// Queries used to clean up server connections after /// client modifications. -#[derive(Default)] #[allow(dead_code)] pub struct Cleanup { - queries: Vec<&'static str>, + queries: &'static Vec, reset: bool, dirty: bool, deallocate: bool, } +impl Default for Cleanup { + fn default() -> Self { + Self { + queries: &*NONE, + reset: false, + dirty: false, + deallocate: false, + } + } +} + impl std::fmt::Display for Cleanup { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.queries.join(",")) + write!( + f, + "{}", + self.queries + .iter() + .map(|s| s.query()) + .collect::>() + .join(",") + ) } } @@ -35,7 +67,7 @@ impl Cleanup { /// Cleanup prepared statements. pub fn prepared_statements() -> Self { Self { - queries: vec!["DEALLOCATE ALL"], + queries: &*PREPARED, deallocate: true, ..Default::default() } @@ -44,7 +76,7 @@ impl Cleanup { /// Cleanup parameters. pub fn parameters() -> Self { Self { - queries: vec!["RESET ALL", "DISCARD ALL"], + queries: &*PARAMS, dirty: true, ..Default::default() } @@ -56,16 +88,13 @@ impl Cleanup { reset: true, dirty: true, deallocate: true, - queries: vec!["RESET ALL", "DISCARD ALL", "DEALLOCATE ALL"], + queries: &*ALL, } } /// Nothing to clean up. pub fn none() -> Self { - Self { - queries: vec![], - ..Default::default() - } + Self::default() } /// Cleanup needed? @@ -74,8 +103,8 @@ impl Cleanup { } /// Get queries to execute on the server to perform cleanup. - pub fn queries(&self) -> &[&str] { - &self.queries + pub fn queries(&self) -> &[Query] { + self.queries } pub fn is_reset_params(&self) -> bool { diff --git a/pgdog/src/backend/pool/cluster.rs b/pgdog/src/backend/pool/cluster.rs index c6a4cbda..afe9590f 100644 --- a/pgdog/src/backend/pool/cluster.rs +++ b/pgdog/src/backend/pool/cluster.rs @@ -1,20 +1,23 @@ //! A collection of replicas and a primary. +use parking_lot::RwLock; +use std::sync::Arc; +use tokio::spawn; +use tracing::{error, info}; + use crate::{ backend::{ databases::databases, replication::{ReplicationConfig, ShardedColumn}, - ShardedTables, + Schema, ShardedTables, }, - config::{General, PoolerMode, ShardedTable, User}, + config::{General, MultiTenant, PoolerMode, ReadWriteStrategy, ShardedTable, User}, net::messages::BackendKeyData, }; use super::{Address, Config, Error, Guard, Request, Shard}; use crate::config::LoadBalancingStrategy; -use std::ffi::CString; - #[derive(Clone, Debug)] /// Database configuration. pub struct PoolConfig { @@ -30,10 +33,15 @@ pub struct PoolConfig { pub struct Cluster { name: String, shards: Vec, + user: String, password: String, pooler_mode: PoolerMode, sharded_tables: ShardedTables, replication_sharding: Option, + mirror_of: Option, + schema: Arc>, + multi_tenant: Option, + rw_strategy: ReadWriteStrategy, } /// Sharding configuration from the cluster. @@ -55,10 +63,14 @@ pub struct ClusterConfig<'a> { pub name: &'a str, pub shards: &'a [ClusterShardConfig], pub lb_strategy: LoadBalancingStrategy, + pub user: &'a str, pub password: &'a str, pub pooler_mode: PoolerMode, pub sharded_tables: ShardedTables, pub replication_sharding: Option, + pub mirror_of: Option<&'a str>, + pub multi_tenant: &'a Option, + pub rw_strategy: ReadWriteStrategy, } impl<'a> ClusterConfig<'a> { @@ -67,15 +79,21 @@ impl<'a> ClusterConfig<'a> { user: &'a User, shards: &'a [ClusterShardConfig], sharded_tables: ShardedTables, + mirror_of: Option<&'a str>, + multi_tenant: &'a Option, ) -> Self { Self { name: &user.database, password: user.password(), + user: &user.name, replication_sharding: user.replication_sharding.clone(), pooler_mode: user.pooler_mode.unwrap_or(general.pooler_mode), lb_strategy: general.load_balancing_strategy, shards, sharded_tables, + mirror_of, + multi_tenant, + rw_strategy: general.read_write_strategy, } } } @@ -87,10 +105,14 @@ impl Cluster { name, shards, lb_strategy, + user, password, pooler_mode, sharded_tables, replication_sharding, + mirror_of, + multi_tenant, + rw_strategy, } = config; Self { @@ -100,9 +122,14 @@ impl Cluster { .collect(), name: name.to_owned(), password: password.to_owned(), + user: user.to_owned(), pooler_mode, sharded_tables, replication_sharding, + mirror_of: mirror_of.map(|s| s.to_owned()), + schema: Arc::new(RwLock::new(Schema::default())), + multi_tenant: multi_tenant.clone(), + rw_strategy, } } @@ -143,10 +170,15 @@ impl Cluster { Self { shards: self.shards.iter().map(|s| s.duplicate()).collect(), name: self.name.clone(), + user: self.user.clone(), password: self.password.clone(), pooler_mode: self.pooler_mode, sharded_tables: self.sharded_tables.clone(), replication_sharding: self.replication_sharding.clone(), + mirror_of: self.mirror_of.clone(), + schema: self.schema.clone(), + multi_tenant: self.multi_tenant.clone(), + rw_strategy: self.rw_strategy, } } @@ -164,50 +196,9 @@ impl Cluster { &self.shards } - /// Plugin input. - /// - /// # Safety - /// - /// This allocates, so make sure to call `Config::drop` when you're done. - /// - pub unsafe fn plugin_config(&self) -> Result { - use pgdog_plugin::bindings::{Config, DatabaseConfig, Role_PRIMARY, Role_REPLICA}; - let mut databases: Vec = vec![]; - let name = CString::new(self.name.as_str()).map_err(|_| Error::NullBytes)?; - - for (index, shard) in self.shards.iter().enumerate() { - if let Some(ref primary) = shard.primary { - // Ignore hosts with null bytes. - let host = if let Ok(host) = CString::new(primary.addr().host.as_str()) { - host - } else { - continue; - }; - databases.push(DatabaseConfig::new( - host, - primary.addr().port, - Role_PRIMARY, - index, - )); - } - - for replica in shard.replicas.pools() { - // Ignore hosts with null bytes. - let host = if let Ok(host) = CString::new(replica.addr().host.as_str()) { - host - } else { - continue; - }; - databases.push(DatabaseConfig::new( - host, - replica.addr().port, - Role_REPLICA, - index, - )); - } - } - - Ok(Config::new(name, &databases, self.shards.len())) + /// Mirrors getter. + pub fn mirror_of(&self) -> Option<&str> { + self.mirror_of.as_deref() } /// Get the password the user should use to connect to the database. @@ -215,6 +206,16 @@ impl Cluster { &self.password } + /// User name. + pub fn user(&self) -> &str { + &self.user + } + + /// Cluster name (database name). + pub fn name(&self) -> &str { + &self.name + } + /// Get pooler mode. pub fn pooler_mode(&self) -> PoolerMode { self.pooler_mode @@ -252,6 +253,11 @@ impl Cluster { true } + /// Multi-tenant config. + pub fn multi_tenant(&self) -> &Option { + &self.multi_tenant + } + /// Get replication configuration for this cluster. pub fn replication_sharding_config(&self) -> Option { self.replication_sharding @@ -267,11 +273,47 @@ impl Cluster { } } + /// Update schema from primary. + async fn update_schema(&self) -> Result<(), crate::backend::Error> { + let mut server = self.primary(0, &Request::default()).await?; + let schema = Schema::load(&mut server).await?; + info!( + "loaded {} tables from schema [{}]", + schema.tables().len(), + server.addr() + ); + *self.schema.write() = schema; + Ok(()) + } + + fn load_schema(&self) -> bool { + self.multi_tenant.is_some() + } + + /// Get currently loaded schema. + pub fn schema(&self) -> Schema { + self.schema.read().clone() + } + + /// Read/write strategy + pub fn read_write_strategy(&self) -> &ReadWriteStrategy { + &self.rw_strategy + } + /// Launch the connection pools. pub(crate) fn launch(&self) { for shard in self.shards() { shard.launch(); } + + if self.load_schema() { + let me = self.clone(); + spawn(async move { + if let Err(err) = me.update_schema().await { + error!("error loading schema: {}", err); + } + }); + } } /// Shutdown the connection pools. @@ -286,7 +328,7 @@ impl Cluster { mod test { use crate::{ backend::{Shard, ShardedTables}, - config::{DataType, ShardedTable}, + config::{DataType, ReadWriteStrategy, ShardedTable}, }; use super::Cluster; @@ -312,5 +354,9 @@ mod test { ..Default::default() } } + + pub fn set_read_write_strategy(&mut self, rw_strategy: ReadWriteStrategy) { + self.rw_strategy = rw_strategy; + } } } diff --git a/pgdog/src/backend/pool/config.rs b/pgdog/src/backend/pool/config.rs index 7640d51f..adfde401 100644 --- a/pgdog/src/backend/pool/config.rs +++ b/pgdog/src/backend/pool/config.rs @@ -14,99 +14,101 @@ pub struct Config { /// Maximum connections allowed in the pool. pub max: usize, /// How long to wait for a connection before giving up. - pub checkout_timeout: u64, // ms + pub checkout_timeout: Duration, // ms /// Close connections that have been idle for longer than this. - pub idle_timeout: u64, // ms + pub idle_timeout: Duration, // ms /// How long to wait for connections to be created. - pub connect_timeout: u64, // ms + pub connect_timeout: Duration, // ms /// How long a connection can be open. - pub max_age: u64, + pub max_age: Duration, /// Can this pool be banned from serving traffic? pub bannable: bool, /// Healtheck timeout. - pub healthcheck_timeout: u64, // ms + pub healthcheck_timeout: Duration, // ms /// Healtcheck interval. - pub healthcheck_interval: u64, // ms + pub healthcheck_interval: Duration, // ms /// Idle healthcheck interval. - pub idle_healthcheck_interval: u64, // ms + pub idle_healthcheck_interval: Duration, // ms /// Idle healthcheck delay. - pub idle_healthcheck_delay: u64, // ms + pub idle_healthcheck_delay: Duration, // ms /// Read timeout (dangerous). - pub read_timeout: u64, // ms + pub read_timeout: Duration, // ms /// Write timeout (dangerous). - pub write_timeout: u64, // ms + pub write_timeout: Duration, // ms /// Query timeout (dangerous). - pub query_timeout: u64, // ms + pub query_timeout: Duration, // ms /// Max ban duration. - pub ban_timeout: u64, // ms + pub ban_timeout: Duration, // ms /// Rollback timeout for dirty connections. - pub rollback_timeout: u64, + pub rollback_timeout: Duration, /// Statement timeout - pub statement_timeout: Option, + pub statement_timeout: Option, /// Replication mode. pub replication_mode: bool, /// Pooler mode. pub pooler_mode: PoolerMode, + /// Read only mode. + pub read_only: bool, } impl Config { /// Connect timeout duration. pub fn connect_timeout(&self) -> Duration { - Duration::from_millis(self.checkout_timeout) + self.connect_timeout } /// Checkout timeout duration. pub fn checkout_timeout(&self) -> Duration { - Duration::from_millis(self.checkout_timeout) + self.checkout_timeout } /// Idle timeout duration. pub fn idle_timeout(&self) -> Duration { - Duration::from_millis(self.idle_timeout) + self.idle_timeout } /// Max age duration. pub fn max_age(&self) -> Duration { - Duration::from_millis(self.max_age) + self.max_age } /// Healthcheck timeout. pub fn healthcheck_timeout(&self) -> Duration { - Duration::from_millis(self.healthcheck_timeout) + self.healthcheck_timeout } /// How long to wait between healtchecks. pub fn healthcheck_interval(&self) -> Duration { - Duration::from_millis(self.healthcheck_interval) + self.healthcheck_interval } /// Idle healtcheck interval. pub fn idle_healthcheck_interval(&self) -> Duration { - Duration::from_millis(self.idle_healthcheck_interval) + self.idle_healthcheck_interval } /// Idle healtcheck delay. pub fn idle_healthcheck_delay(&self) -> Duration { - Duration::from_millis(self.idle_healthcheck_delay) + self.idle_healthcheck_delay } /// Ban timeout. pub fn ban_timeout(&self) -> Duration { - Duration::from_millis(self.ban_timeout) + self.ban_timeout } /// Rollback timeout. pub fn rollback_timeout(&self) -> Duration { - Duration::from_millis(self.rollback_timeout) + self.rollback_timeout } /// Read timeout. pub fn read_timeout(&self) -> Duration { - Duration::from_millis(self.read_timeout) + self.read_timeout } pub fn query_timeout(&self) -> Duration { - Duration::from_millis(self.query_timeout) + self.query_timeout } /// Default config for a primary. @@ -132,26 +134,31 @@ impl Config { max: database .pool_size .unwrap_or(user.pool_size.unwrap_or(general.default_pool_size)), - healthcheck_interval: general.healthcheck_interval, - idle_healthcheck_interval: general.idle_healthcheck_interval, - idle_healthcheck_delay: general.idle_healthcheck_delay, - ban_timeout: general.ban_timeout, - rollback_timeout: general.rollback_timeout, + healthcheck_interval: Duration::from_millis(general.healthcheck_interval), + idle_healthcheck_interval: Duration::from_millis(general.idle_healthcheck_interval), + idle_healthcheck_delay: Duration::from_millis(general.idle_healthcheck_delay), + ban_timeout: Duration::from_millis(general.ban_timeout), + rollback_timeout: Duration::from_millis(general.rollback_timeout), statement_timeout: if let Some(statement_timeout) = database.statement_timeout { Some(statement_timeout) } else { user.statement_timeout - }, + } + .map(Duration::from_millis), replication_mode: user.replication_mode, pooler_mode: database .pooler_mode .unwrap_or(user.pooler_mode.unwrap_or(general.pooler_mode)), - connect_timeout: general.connect_timeout, - query_timeout: general.query_timeout, - checkout_timeout: general.checkout_timeout, - idle_timeout: user - .idle_timeout - .unwrap_or(database.idle_timeout.unwrap_or(general.idle_timeout)), + connect_timeout: Duration::from_millis(general.connect_timeout), + query_timeout: Duration::from_millis(general.query_timeout), + checkout_timeout: Duration::from_millis(general.checkout_timeout), + idle_timeout: Duration::from_millis( + user.idle_timeout + .unwrap_or(database.idle_timeout.unwrap_or(general.idle_timeout)), + ), + read_only: database + .read_only + .unwrap_or(user.read_only.unwrap_or_default()), ..Default::default() } } @@ -162,23 +169,24 @@ impl Default for Config { Self { min: 1, max: 10, - checkout_timeout: 5_000, - idle_timeout: 60_000, - connect_timeout: 5_000, - max_age: 24 * 3600 * 1000, + checkout_timeout: Duration::from_millis(5_000), + idle_timeout: Duration::from_millis(60_000), + connect_timeout: Duration::from_millis(5_000), + max_age: Duration::from_millis(24 * 3600 * 1000), bannable: true, - healthcheck_timeout: 5_000, - healthcheck_interval: 30_000, - idle_healthcheck_interval: 5_000, - idle_healthcheck_delay: 5_000, - read_timeout: Duration::MAX.as_millis() as u64, - write_timeout: Duration::MAX.as_millis() as u64, - query_timeout: Duration::MAX.as_millis() as u64, - ban_timeout: Duration::from_secs(300).as_millis() as u64, - rollback_timeout: Duration::from_secs(5).as_millis() as u64, + healthcheck_timeout: Duration::from_millis(5_000), + healthcheck_interval: Duration::from_millis(30_000), + idle_healthcheck_interval: Duration::from_millis(5_000), + idle_healthcheck_delay: Duration::from_millis(5_000), + read_timeout: Duration::MAX, + write_timeout: Duration::MAX, + query_timeout: Duration::MAX, + ban_timeout: Duration::from_secs(300), + rollback_timeout: Duration::from_secs(5), statement_timeout: None, replication_mode: false, pooler_mode: PoolerMode::default(), + read_only: false, } } } diff --git a/pgdog/src/backend/pool/connection/binding.rs b/pgdog/src/backend/pool/connection/binding.rs index 9e950283..8445596a 100644 --- a/pgdog/src/backend/pool/connection/binding.rs +++ b/pgdog/src/backend/pool/connection/binding.rs @@ -1,6 +1,6 @@ //! Binding between frontend client and a connection on the backend. -use crate::{backend::ProtocolMessage, net::parameter::Parameters}; +use crate::{backend::ProtocolMessage, net::parameter::Parameters, state::State}; use super::*; @@ -29,6 +29,23 @@ impl Binding { } } + pub(super) fn force_close(&mut self) { + match self { + Binding::Server(Some(ref mut guard)) => guard.stats_mut().state(State::ForceClose), + Binding::MultiShard(ref mut guards, _) => { + for guard in guards { + guard.stats_mut().state(State::ForceClose); + } + } + Binding::Replication(Some(ref mut guard), _) => { + guard.stats_mut().state(State::ForceClose); + } + _ => (), + } + + self.disconnect(); + } + pub(super) fn connected(&self) -> bool { match self { Binding::Server(server) => server.is_some(), @@ -45,6 +62,7 @@ impl Binding { guard.read().await } else { loop { + debug!("binding suspended"); sleep(Duration::MAX).await } } @@ -54,6 +72,7 @@ impl Binding { Binding::MultiShard(shards, state) => { if shards.is_empty() { loop { + debug!("multi-shard binding suspended"); sleep(Duration::MAX).await; } } else { @@ -64,26 +83,27 @@ impl Binding { if let Some(message) = state.message() { return Ok(message); } + let mut read = false; + for server in shards.iter_mut() { + if !server.has_more_messages() { + continue; + } - let pending = shards - .iter_mut() - .filter(|s| s.has_more_messages()) - .collect::>(); - - if pending.is_empty() { - break; - } - - for shard in pending { - let message = shard.read().await?; + let message = server.read().await?; + read = true; if let Some(message) = state.forward(message)? { return Ok(message); } } + + if !read { + break; + } } loop { state.reset(); + debug!("multi-shard binding done"); sleep(Duration::MAX).await; } } @@ -112,10 +132,7 @@ impl Binding { } } - pub(super) async fn send( - &mut self, - messages: Vec + Clone>, - ) -> Result<(), Error> { + pub(super) async fn send(&mut self, messages: &crate::frontend::Buffer) -> Result<(), Error> { match self { Binding::Server(server) => { if let Some(server) = server { @@ -128,7 +145,7 @@ impl Binding { Binding::Admin(backend) => Ok(backend.send(messages).await?), Binding::MultiShard(servers, _state) => { for server in servers.iter_mut() { - server.send(messages.clone()).await?; + server.send(messages).await?; } Ok(()) @@ -152,17 +169,23 @@ impl Binding { match row.shard() { Shard::Direct(row_shard) => { if shard == *row_shard { - server.send_one(row.message()).await?; + server + .send_one(&ProtocolMessage::from(row.message())) + .await?; } } Shard::All => { - server.send_one(row.message()).await?; + server + .send_one(&ProtocolMessage::from(row.message())) + .await?; } Shard::Multi(multi) => { if multi.contains(&shard) { - server.send_one(row.message()).await?; + server + .send_one(&ProtocolMessage::from(row.message())) + .await?; } } } @@ -185,6 +208,24 @@ impl Binding { } } + pub(super) fn state_check(&self, state: State) -> bool { + match self { + Binding::Server(Some(server)) => { + debug!( + "server is in \"{}\" state [{}]", + server.stats().state, + server.addr() + ); + server.stats().state == state + } + Binding::MultiShard(servers, _) => servers.iter().all(|s| { + debug!("server is in \"{}\" state [{}]", s.stats().state, s.addr()); + s.stats().state == state + }), + _ => true, + } + } + /// Execute a query on all servers. pub(super) async fn execute(&mut self, query: &str) -> Result<(), Error> { match self { @@ -208,28 +249,20 @@ impl Binding { Ok(()) } - pub(super) async fn link_client( - &mut self, - params: &Parameters, - prepared_statements: bool, - ) -> Result { + pub(super) async fn link_client(&mut self, params: &Parameters) -> Result { match self { - Binding::Server(Some(ref mut server)) => { - server.link_client(params, prepared_statements).await - } + Binding::Server(Some(ref mut server)) => server.link_client(params).await, Binding::MultiShard(ref mut servers, _) => { let mut max = 0; for server in servers { - let synced = server.link_client(params, prepared_statements).await?; + let synced = server.link_client(params).await?; if max < synced { max = synced; } } Ok(max) } - Binding::Replication(Some(ref mut server), _) => { - server.link_client(params, prepared_statements).await - } + Binding::Replication(Some(ref mut server), _) => server.link_client(params).await, _ => Ok(0), } diff --git a/pgdog/src/backend/pool/connection/mirror.rs b/pgdog/src/backend/pool/connection/mirror.rs new file mode 100644 index 00000000..d319d179 --- /dev/null +++ b/pgdog/src/backend/pool/connection/mirror.rs @@ -0,0 +1,145 @@ +use tokio::select; +use tokio::time::timeout; +use tokio::{spawn, sync::mpsc::*}; +use tracing::{debug, error}; + +use crate::backend::Cluster; +use crate::config::config; +use crate::frontend::client::timeouts::Timeouts; +use crate::frontend::{PreparedStatements, Router, RouterContext}; +use crate::net::Parameters; +use crate::state::State; +use crate::{ + backend::pool::{Error as PoolError, Request}, + frontend::Buffer, +}; + +use super::Connection; +use super::Error; + +#[derive(Clone, Debug)] +pub(crate) struct MirrorRequest { + pub(super) request: Request, + pub(super) buffer: Buffer, +} + +impl MirrorRequest { + pub(crate) fn new(buffer: &Buffer) -> Self { + Self { + request: Request::default(), + buffer: buffer.clone(), + } + } +} + +#[derive(Debug)] +pub(crate) struct Mirror { + connection: Connection, + router: Router, + cluster: Cluster, + prepared_statements: PreparedStatements, + params: Parameters, + state: State, +} + +impl Mirror { + pub(crate) fn spawn(cluster: &Cluster) -> Result { + let connection = Connection::new(cluster.user(), cluster.name(), false)?; + + let mut mirror = Self { + connection, + router: Router::new(), + prepared_statements: PreparedStatements::new(), + cluster: cluster.clone(), + state: State::Idle, + params: Parameters::default(), + }; + + let config = config(); + + let query_timeout = Timeouts::from_config(&config.config.general); + let (tx, mut rx) = channel(config.config.general.mirror_queue); + let handler = MirrorHandler { tx }; + + spawn(async move { + loop { + let qt = query_timeout.query_timeout(&mirror.state); + select! { + req = rx.recv() => { + if let Some(req) = req { + // TODO: timeout these. + if let Err(err) = mirror.handle(&req).await { + if !matches!(err, Error::Pool(PoolError::Offline | PoolError::AllReplicasDown | PoolError::Banned)) { + error!("mirror error: {}", err); + } + + mirror.connection.force_close(); + mirror.state = State::Idle; + } else { + mirror.state = State::Active; + } + } else { + debug!("mirror connection shutting down"); + break; + } + } + + message = timeout(qt, mirror.connection.read()) => { + match message { + Err(_) => { + error!("mirror query timeout"); + mirror.connection.force_close(); + } + Ok(Err(err)) => { + error!("mirror error: {}", err); + mirror.connection.disconnect(); + } + Ok(_) => (), + } + + if mirror.connection.done() { + mirror.connection.disconnect(); + mirror.router.reset(); + mirror.state = State::Idle; + } + } + } + } + }); + + Ok(handler) + } + + pub(crate) async fn handle(&mut self, request: &MirrorRequest) -> Result<(), Error> { + if !self.connection.connected() { + // TODO: handle parsing errors. + if let Ok(context) = RouterContext::new( + &request.buffer, + &self.cluster, + &mut self.prepared_statements, + &self.params, + ) { + if let Err(err) = self.router.query(context) { + error!("mirror query parse error: {}", err); + return Ok(()); // Drop request. + } + + self.connection + .connect(&request.request, &self.router.route()) + .await?; + } + } + + // TODO: handle streaming. + self.connection + .handle_buffer(&request.buffer, &mut self.router, false) + .await?; + + Ok(()) + } +} + +#[derive(Debug)] +pub(crate) struct MirrorHandler { + pub(super) tx: Sender, +} diff --git a/pgdog/src/backend/pool/connection/mod.rs b/pgdog/src/backend/pool/connection/mod.rs index 49e7be89..5ca5f92f 100644 --- a/pgdog/src/backend/pool/connection/mod.rs +++ b/pgdog/src/backend/pool/connection/mod.rs @@ -1,17 +1,23 @@ //! Server connection requested by a frontend. +use mirror::{MirrorHandler, MirrorRequest}; use tokio::time::sleep; +use tracing::debug; use crate::{ admin::backend::Backend, backend::{ databases::databases, + reload_notify, replication::{Buffer, ReplicationConfig}, - ProtocolMessage, }, config::PoolerMode, - frontend::router::{parser::Shard, CopyRow, Route}, + frontend::{ + router::{parser::Shard, CopyRow, Route}, + Router, + }, net::{Bind, Message, ParameterStatus, Parameters}, + state::State, }; use super::{ @@ -24,19 +30,22 @@ use std::{mem::replace, time::Duration}; pub mod aggregate; pub mod binding; pub mod buffer; +pub mod mirror; pub mod multi_shard; use aggregate::Aggregates; use binding::Binding; +use mirror::Mirror; use multi_shard::MultiShard; /// Wrapper around a server connection. -#[derive(Default)] +#[derive(Default, Debug)] pub struct Connection { user: String, database: String, binding: Binding, cluster: Option, + mirrors: Vec, } impl Connection { @@ -51,6 +60,7 @@ impl Connection { cluster: None, user: user.to_owned(), database: database.to_owned(), + mirrors: vec![], }; if !admin { @@ -74,9 +84,14 @@ impl Connection { }; if connect { + debug!("connecting {}", route); match self.try_conn(request, route).await { Ok(()) => (), Err(Error::Pool(super::Error::Offline | super::Error::AllReplicasDown)) => { + // Wait to reload pools until they are ready. + if let Some(wait) = reload_notify::ready() { + wait.await; + } self.reload()?; return self.try_conn(request, route).await; } @@ -84,6 +99,10 @@ impl Connection { return Err(err); } } + + if !self.binding.state_check(State::Idle) { + return Err(Error::NotInSync); + } } Ok(()) @@ -103,6 +122,13 @@ impl Connection { Ok(()) } + /// Send traffic to mirrors. + pub(crate) fn mirror(&self, buffer: &crate::frontend::Buffer) { + for mirror in &self.mirrors { + let _ = mirror.tx.try_send(MirrorRequest::new(buffer)); + } + } + /// Try to get a connection for the given route. async fn try_conn(&mut self, request: &Request, route: &Route) -> Result<(), Error> { if let Shard::Direct(shard) = route.shard() { @@ -169,13 +195,16 @@ impl Connection { match &self.binding { Binding::Admin(_) => Ok(ParameterStatus::fake()), _ => { - self.connect(request, &Route::read(Some(0))).await?; // Get params from any replica. - let params = self - .server()? - .params() - .iter() - .map(ParameterStatus::from) - .collect(); + // Try a replica. If not, try the primary. + if self.connect(request, &Route::read(Some(0))).await.is_err() { + self.connect(request, &Route::write(Some(0))).await?; + }; + let mut params = vec![]; + for param in self.server()?.params().iter() { + if let Some(value) = param.1.as_str() { + params.push(ParameterStatus::from((param.0.as_str(), value))); + } + } self.disconnect(); Ok(params) } @@ -187,6 +216,11 @@ impl Connection { self.binding.disconnect(); } + /// Close the connection without banning the pool. + pub(crate) fn force_close(&mut self) { + self.binding.force_close() + } + /// Read a message from the server connection. /// /// Only await this future inside a `select!`. One of the conditions @@ -197,10 +231,7 @@ impl Connection { } /// Send messages to the server. - pub(crate) async fn send( - &mut self, - messages: Vec + Clone>, - ) -> Result<(), Error> { + pub(crate) async fn send(&mut self, messages: &crate::frontend::Buffer) -> Result<(), Error> { self.binding.send(messages).await } @@ -209,12 +240,49 @@ impl Connection { self.binding.send_copy(rows).await } + /// Send buffer in a potentially sharded context. + pub(crate) async fn handle_buffer( + &mut self, + messages: &crate::frontend::Buffer, + router: &mut Router, + streaming: bool, + ) -> Result<(), Error> { + if messages.copy() && !streaming { + let rows = router.copy_data(messages).unwrap(); + if !rows.is_empty() { + self.send_copy(rows).await?; + self.send(&messages.without_copy_data()).await?; + } else { + self.send(messages).await?; + } + } else { + // Send query to server. + self.send(messages).await?; + } + + Ok(()) + } + /// Fetch the cluster from the global database store. pub(crate) fn reload(&mut self) -> Result<(), Error> { match self.binding { Binding::Server(_) | Binding::MultiShard(_, _) | Binding::Replication(_, _) => { - let cluster = databases().cluster((self.user.as_str(), self.database.as_str()))?; + let databases = databases(); + let user = (self.user.as_str(), self.database.as_str()); + let cluster = databases.cluster(user)?; + self.cluster = Some(cluster); + self.mirrors = databases + .mirrors(user)? + .unwrap_or(&[]) + .iter() + .map(Mirror::spawn) + .collect::, Error>>()?; + debug!( + r#"database "{}" has {} mirrors"#, + self.cluster()?.name(), + self.mirrors.len() + ); } _ => (), @@ -285,12 +353,8 @@ impl Connection { self.binding.execute(query).await } - pub(crate) async fn link_client( - &mut self, - params: &Parameters, - prepared_statements: bool, - ) -> Result { - self.binding.link_client(params, prepared_statements).await + pub(crate) async fn link_client(&mut self, params: &Parameters) -> Result { + self.binding.link_client(params).await } pub(crate) fn changed_params(&mut self) -> Parameters { diff --git a/pgdog/src/backend/pool/connection/multi_shard/mod.rs b/pgdog/src/backend/pool/connection/multi_shard/mod.rs index 57c9c22c..e6399f7a 100644 --- a/pgdog/src/backend/pool/connection/multi_shard/mod.rs +++ b/pgdog/src/backend/pool/connection/multi_shard/mod.rs @@ -16,6 +16,8 @@ use crate::{ use super::buffer::Buffer; mod context; +#[cfg(test)] +mod test; #[derive(Default, Debug)] struct Counters { @@ -212,7 +214,7 @@ impl MultiShard { if self.decoder.rd().fields.is_empty() && !bind.anonymous() { if let Some(rd) = PreparedStatements::global() .lock() - .row_description(&bind.statement) + .row_description(bind.statement()) { self.decoder.row_description(&rd); } diff --git a/pgdog/src/backend/pool/connection/multi_shard/test.rs b/pgdog/src/backend/pool/connection/multi_shard/test.rs new file mode 100644 index 00000000..9b4bf7a0 --- /dev/null +++ b/pgdog/src/backend/pool/connection/multi_shard/test.rs @@ -0,0 +1,61 @@ +use crate::net::{DataRow, Field}; + +use super::*; + +#[test] +fn test_rd_before_dr() { + let mut multi_shard = MultiShard::new(3, &Route::read(None)); + let rd = RowDescription::new(&[Field::bigint("id")]); + let mut dr = DataRow::new(); + dr.add(1i64); + for _ in 0..2 { + let result = multi_shard + .forward(rd.message().unwrap().backend()) + .unwrap(); + assert!(result.is_none()); // dropped + let result = multi_shard + .forward(dr.message().unwrap().backend()) + .unwrap(); + assert!(result.is_none()); // buffered. + } + + let result = multi_shard.forward(rd.message().unwrap()).unwrap(); + assert_eq!(result, Some(rd.message().unwrap())); + let result = multi_shard.message(); + // Waiting for command complete + assert!(result.is_none()); + + for _ in 0..3 { + let result = multi_shard + .forward( + CommandComplete::from_str("SELECT 1") + .message() + .unwrap() + .backend(), + ) + .unwrap(); + assert!(result.is_none()); + } + + for _ in 0..2 { + let result = multi_shard.message(); + assert_eq!( + result.map(|m| m.backend()), + Some(dr.message().unwrap().backend()) + ); + } + + let result = multi_shard.message().map(|m| m.backend()); + assert_eq!( + result, + Some( + CommandComplete::from_str("SELECT 3") + .message() + .unwrap() + .backend() + ) + ); + + // Buffer is empty. + assert!(multi_shard.message().is_none()); +} diff --git a/pgdog/src/backend/pool/guard.rs b/pgdog/src/backend/pool/guard.rs index 3d3f4bb9..61480947 100644 --- a/pgdog/src/backend/pool/guard.rs +++ b/pgdog/src/backend/pool/guard.rs @@ -2,17 +2,18 @@ use std::ops::{Deref, DerefMut}; -use tokio::spawn; use tokio::time::timeout; +use tokio::{spawn, time::Instant}; use tracing::{debug, error}; use crate::backend::Server; +use super::Error; use super::{cleanup::Cleanup, Pool}; /// Connection guard. pub struct Guard { - server: Option, + server: Option>, pub(super) pool: Pool, pub(super) reset: bool, } @@ -34,7 +35,9 @@ impl std::fmt::Debug for Guard { impl Guard { /// Create new connection guard. - pub fn new(pool: Pool, server: Server) -> Self { + pub fn new(pool: Pool, mut server: Box, granted_at: Instant) -> Self { + server.stats_mut().set_timers(granted_at); + Self { server: Some(server), pool, @@ -52,58 +55,108 @@ impl Guard { let rollback = server.in_transaction(); let cleanup = Cleanup::new(self, &server); let reset = cleanup.needed(); - let schema_changed = server.schema_changed(); let sync_prepared = server.sync_prepared(); + let needs_drain = server.needs_drain(); + let force_close = server.force_close(); server.reset_changed_params(); // No need to delay checkin unless we have to. - if rollback || reset || sync_prepared { - let rollback_timeout = pool.lock().config.rollback_timeout(); + if (rollback || reset || sync_prepared || needs_drain) && !force_close { + let rollback_timeout = pool.inner().config.rollback_timeout(); spawn(async move { - // Rollback any unfinished transactions, - // but only if the server is in sync (protocol-wise). - if rollback && timeout(rollback_timeout, server.rollback()).await.is_err() { + if timeout( + rollback_timeout, + Self::cleanup_internal(&mut server, cleanup), + ) + .await + .is_err() + { error!("rollback timeout [{}]", server.addr()); - } - - if cleanup.needed() { - if timeout(rollback_timeout, server.execute_batch(cleanup.queries())) - .await - .is_err() - { - error!("reset timeout [{}]", server.addr()); - } else { - debug!("{} [{}]", cleanup, server.addr()); - server.cleaned(); - } - } - - if schema_changed { - server.reset_schema_changed(); - } - - if cleanup.is_reset_params() { - server.reset_params(); - } - - if sync_prepared { - if let Err(err) = server.sync_prepared_statements().await { - error!( - "prepared statements sync error: {:?} [{}]", - err, - server.addr() - ); - } - } + }; pool.checkin(server); }); } else { + debug!( + "[cleanup] no cleanup needed, server in \"{}\" state [{}]", + server.stats().state, + server.addr(), + ); pool.checkin(server); } } } + + async fn cleanup_internal(server: &mut Box, cleanup: Cleanup) -> Result<(), Error> { + let schema_changed = server.schema_changed(); + let sync_prepared = server.sync_prepared(); + let needs_drain = server.needs_drain(); + + if needs_drain { + // Receive whatever data the client left before disconnecting. + debug!( + "[cleanup] draining data from \"{}\" server [{}]", + server.stats().state, + server.addr() + ); + server.drain().await; + } + let rollback = server.in_transaction(); + + // Rollback any unfinished transactions, + // but only if the server is in sync (protocol-wise). + if rollback { + debug!( + "[cleanup] rolling back server transaction, in \"{}\" state [{}]", + server.stats().state, + server.addr(), + ); + server.rollback().await; + } + + if cleanup.needed() { + debug!( + "[cleanup] {}, server in \"{}\" state [{}]", + cleanup, + server.stats().state, + server.addr() + ); + match server.execute_batch(cleanup.queries()).await { + Err(_) => { + error!("server reset error [{}]", server.addr()); + } + Ok(_) => { + server.cleaned(); + } + } + } + + if schema_changed { + server.reset_schema_changed(); + } + + if cleanup.is_reset_params() { + server.reset_params(); + } + + if sync_prepared { + debug!( + "[cleanup] syncing prepared statements, server in \"{}\" state [{}]", + server.stats().state, + server.addr() + ); + if let Err(err) = server.sync_prepared_statements().await { + error!( + "prepared statements sync error: {:?} [{}]", + err, + server.addr() + ); + } + } + + Ok(()) + } } impl Deref for Guard { diff --git a/pgdog/src/backend/pool/healthcheck.rs b/pgdog/src/backend/pool/healthcheck.rs index 6fbe5967..a9c45c7e 100644 --- a/pgdog/src/backend/pool/healthcheck.rs +++ b/pgdog/src/backend/pool/healthcheck.rs @@ -1,8 +1,9 @@ //! Healtcheck a connection. -use std::time::{Duration, Instant}; +use std::time::Duration; use tokio::time::timeout; +use tokio::time::Instant; use tracing::error; use super::{Error, Pool}; @@ -11,35 +12,44 @@ use crate::backend::Server; /// Perform a healtcheck on a connection. pub struct Healtcheck<'a> { conn: &'a mut Server, - pool: Pool, + pool: &'a Pool, healthcheck_interval: Duration, healthcheck_timeout: Duration, + now: Instant, } impl<'a> Healtcheck<'a> { /// Perform a healtcheck only if necessary. pub fn conditional( conn: &'a mut Server, - pool: Pool, + pool: &'a Pool, healthcheck_interval: Duration, healthcheck_timeout: Duration, + now: Instant, ) -> Self { Self { conn, pool, healthcheck_interval, healthcheck_timeout, + now, } } /// Perform a mandatory healtcheck. - pub fn mandatory(conn: &'a mut Server, pool: Pool, healthcheck_timeout: Duration) -> Self { - Self::conditional(conn, pool, Duration::from_millis(0), healthcheck_timeout) + pub fn mandatory(conn: &'a mut Server, pool: &'a Pool, healthcheck_timeout: Duration) -> Self { + Self::conditional( + conn, + pool, + Duration::from_millis(0), + healthcheck_timeout, + Instant::now(), + ) } /// Perform the healtcheck if it's required. pub async fn healthcheck(&mut self) -> Result<(), Error> { - let healtcheck_age = self.conn.healthcheck_age(Instant::now()); + let healtcheck_age = self.conn.healthcheck_age(self.now); if healtcheck_age < self.healthcheck_interval { return Ok(()); diff --git a/pgdog/src/backend/pool/inner.rs b/pgdog/src/backend/pool/inner.rs index 2f2d3bb4..96530605 100644 --- a/pgdog/src/backend/pool/inner.rs +++ b/pgdog/src/backend/pool/inner.rs @@ -1,34 +1,40 @@ //! Pool internals synchronized with a mutex. +use std::cmp::max; use std::collections::VecDeque; -use std::{cmp::max, time::Instant}; -use crate::backend::Server; +use crate::backend::{stats::Counts as BackendCounts, Server}; use crate::net::messages::BackendKeyData; -use super::{Ban, Config, Error, Mapping, Oids, Pool, Request, Stats}; +use tokio::time::Instant; + +use super::{Ban, Config, Error, Mapping, Oids, Pool, Request, Stats, Taken, Waiter}; /// Pool internals protected by a mutex. #[derive(Default)] pub(super) struct Inner { /// Idle server connections. - conns: VecDeque, + #[allow(clippy::vec_box)] + conns: Vec>, /// Server connections currently checked out. - taken: Vec, + taken: Taken, /// Pool configuration. pub(super) config: Config, /// Number of clients waiting for a connection. - pub(super) waiting: VecDeque, + pub(super) waiting: VecDeque, /// Pool ban status. pub(super) ban: Option, /// Pool is online and available to clients. pub(super) online: bool, /// Pool is paused. pub(super) paused: bool, - /// Connections being created. - pub(super) creating: usize, /// Track out of sync terminations. pub(super) out_of_sync: usize, + /// How many times servers had to be re-synced + /// after back check-in. + pub(super) re_synced: usize, + /// Number of connections that were force closed. + pub(super) force_close: usize, /// Track connections closed with errors. pub(super) errors: usize, /// Stats @@ -44,7 +50,6 @@ pub(super) struct Inner { impl std::fmt::Debug for Inner { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Inner") - .field("creating", &self.creating) .field("paused", &self.paused) .field("taken", &self.taken.len()) .field("conns", &self.conns.len()) @@ -58,15 +63,16 @@ impl Inner { /// New inner structure. pub(super) fn new(config: Config, id: u64) -> Self { Self { - conns: VecDeque::new(), - taken: Vec::new(), + conns: Vec::new(), + taken: Taken::default(), config, waiting: VecDeque::new(), ban: None, online: false, paused: false, - creating: 0, + force_close: 0, out_of_sync: 0, + re_synced: 0, errors: 0, stats: Stats::default(), oids: None, @@ -96,10 +102,7 @@ impl Inner { /// Find the server currently linked to this client, if any. #[inline] pub(super) fn peer(&self, id: &BackendKeyData) -> Option { - self.taken - .iter() - .find(|p| p.client == *id) - .map(|p| p.server) + self.taken.server(id) } /// How many connections can be removed from the pool @@ -133,12 +136,16 @@ impl Inner { let client_needs = below_max && !self.waiting.is_empty() && self.conns.is_empty(); let maintenance_on = self.online && !self.paused; - !self.banned() && maintenance_on && (maintain_min || client_needs) + !self.banned() && (client_needs || maintenance_on && maintain_min) } /// Check if the pool ban should be removed. #[inline] pub(super) fn check_ban(&mut self, now: Instant) -> bool { + if self.ban.is_none() { + return false; + } + let mut unbanned = false; if let Some(ban) = self.ban.take() { if !ban.expired(now) { @@ -154,7 +161,7 @@ impl Inner { /// Close connections that have exceeded the max age. #[inline] pub(crate) fn close_old(&mut self, now: Instant) -> usize { - let max_age = self.config.max_age(); + let max_age = self.config.max_age; let mut removed = 0; self.conns.retain(|c| { @@ -174,7 +181,7 @@ impl Inner { #[inline] pub(crate) fn close_idle(&mut self, now: Instant) -> usize { let (mut remove, mut removed) = (self.can_remove(), 0); - let idle_timeout = self.config.idle_timeout(); + let idle_timeout = self.config.idle_timeout; self.conns.retain(|c| { let idle_for = c.idle_for(now); @@ -198,9 +205,10 @@ impl Inner { } /// Take connection from the idle pool. - pub(super) fn take(&mut self, request: &Request) -> Option { - if let Some(conn) = self.conns.pop_back() { - self.taken.push(Mapping { + #[inline(always)] + pub(super) fn take(&mut self, request: &Request) -> Option> { + if let Some(conn) = self.conns.pop() { + self.taken.take(&Mapping { client: request.id, server: *(conn.id()), }); @@ -211,14 +219,28 @@ impl Inner { } } - /// Place connection back into the pool. + /// Place connection back into the pool + /// or give it to a waiting client. #[inline] - pub(super) fn put(&mut self, conn: Server) { - self.conns.push_back(conn); + pub(super) fn put(&mut self, conn: Box) { + // Try to give it to a client that's been waiting, if any. + let id = *conn.id(); + if let Some(waiter) = self.waiting.pop_front() { + if let Err(conn) = waiter.tx.send(Ok(conn)) { + self.conns.push(conn.unwrap()); + } else { + self.taken.take(&Mapping { + server: id, + client: waiter.request.id, + }); + } + } else { + self.conns.push(conn); + } } #[inline] - pub(super) fn set_taken(&mut self, taken: Vec) { + pub(super) fn set_taken(&mut self, taken: Taken) { self.taken = taken; } @@ -231,7 +253,8 @@ impl Inner { /// Take all idle connections and tell active ones to /// be returned to a different pool instance. #[inline] - pub(super) fn move_conns_to(&mut self, destination: &Pool) -> (Vec, Vec) { + #[allow(clippy::vec_box)] // Server is a very large struct, reading it when moving between contains is expensive. + pub(super) fn move_conns_to(&mut self, destination: &Pool) -> (Vec>, Taken) { self.moved = Some(destination.clone()); let idle = std::mem::take(&mut self.conns).into_iter().collect(); let taken = std::mem::take(&mut self.taken); @@ -239,62 +262,93 @@ impl Inner { (idle, taken) } - #[inline] + #[inline(always)] /// Check a connection back into the pool if it's ok to do so. /// Otherwise, drop the connection and close it. /// /// Return: true if the pool should be banned, false otherwise. - pub(super) fn maybe_check_in(&mut self, mut server: Server, now: Instant) -> bool { + pub(super) fn maybe_check_in( + &mut self, + mut server: Box, + now: Instant, + stats: BackendCounts, + ) -> CheckInResult { + let mut result = CheckInResult { + banned: false, + replenish: true, + }; + if let Some(ref moved) = self.moved { + result.replenish = false; // Prevents deadlocks. if moved.id() != self.id { - moved.lock().maybe_check_in(server, now); - return false; + moved.lock().maybe_check_in(server, now, stats); + return result; } } - let id = *server.id(); - - let index = self - .taken - .iter() - .enumerate() - .find(|(_i, p)| p.server == id) - .map(|(i, _p)| i); - - if let Some(index) = index { - self.taken.remove(index); - } + self.taken.check_in(server.id()); // Update stats - let stats = server.stats_mut().reset_last_checkout(); self.stats.counts = self.stats.counts + stats; // Ban the pool from serving more clients. if server.error() { self.errors += 1; - return self.maybe_ban(now, Error::ServerError); + result.banned = self.maybe_ban(now, Error::ServerError); + return result; } // Pool is offline or paused, connection should be closed. if !self.online || self.paused { - return false; + result.replenish = false; + return result; } // Close connections exceeding max age. - if server.age(now) >= self.config.max_age() { - return false; + if server.age(now) >= self.config.max_age { + return result; + } + + // Force close the connection. + if server.force_close() { + self.force_close += 1; + return result; + } + + if server.re_synced() { + self.re_synced += 1; + server.reset_re_synced(); } // Finally, if the server is ok, // place the connection back into the idle list. - if server.done() { + if server.can_check_in() { self.put(server); } else { self.out_of_sync += 1; } - false + result + } + + #[inline] + pub(super) fn remove_waiter(&mut self, id: &BackendKeyData) { + if let Some(waiter) = self.waiting.pop_front() { + if waiter.request.id != *id { + // Put me back. + self.waiting.push_front(waiter); + + // Slow search, but we should be somewhere towards the front + // if the runtime is doing scheduling correctly. + for (i, waiter) in self.waiting.iter().enumerate() { + if waiter.request.id == *id { + self.waiting.remove(i); + break; + } + } + } + } } /// Ban the pool from serving traffic if that's allowed @@ -308,14 +362,24 @@ impl Inner { ban_timeout: self.config.ban_timeout(), }; self.ban = Some(ban); + + // Tell every waiting client that this pool is busted. + self.close_waiters(Error::Banned); true } else { false } } - /// Remove the pool ban unless it' been manually banned. #[inline] + pub(super) fn close_waiters(&mut self, err: Error) { + for waiter in self.waiting.drain(..) { + let _ = waiter.tx.send(Err(err)); + } + } + + /// Remove the pool ban unless it' been manually banned. + #[inline(always)] pub fn maybe_unban(&mut self) -> bool { let mut unbanned = false; if let Some(ban) = self.ban.take() { @@ -329,27 +393,24 @@ impl Inner { unbanned } - #[inline] + #[inline(always)] pub fn banned(&self) -> bool { self.ban.is_some() } +} - #[inline] - pub fn created(&mut self) { - self.creating -= 1; - } - - /// Create a create permit. - #[inline] - pub fn creating(&mut self) { - self.creating += 1; - } +#[derive(Debug, Copy, Clone)] +pub(super) struct CheckInResult { + pub(super) banned: bool, + pub(super) replenish: bool, } #[cfg(test)] mod test { use std::time::Duration; + use tokio::sync::oneshot::channel; + use crate::net::messages::BackendKeyData; use super::*; @@ -385,36 +446,55 @@ mod test { assert!(banned); // Testing check-in server. - let banned = inner.maybe_check_in(Server::default(), Instant::now()); - assert!(!banned); + let result = inner.maybe_check_in( + Box::new(Server::default()), + Instant::now(), + BackendCounts::default(), + ); + assert!(!result.banned); assert_eq!(inner.idle(), 0); // pool offline inner.online = true; inner.paused = true; - inner.maybe_check_in(Server::default(), Instant::now()); + inner.maybe_check_in( + Box::new(Server::default()), + Instant::now(), + BackendCounts::default(), + ); assert_eq!(inner.total(), 0); // pool paused; inner.paused = false; - assert!(!inner.maybe_check_in(Server::default(), Instant::now())); + assert!( + !inner + .maybe_check_in( + Box::new(Server::default()), + Instant::now(), + BackendCounts::default() + ) + .banned + ); assert!(inner.idle() > 0); assert_eq!(inner.idle(), 1); - let server = Server::new_error(); + let server = Box::new(Server::new_error()); assert_eq!(inner.checked_out(), 0); - inner.taken.push(Mapping { + inner.taken.take(&Mapping { client: BackendKeyData::new(), server: *server.id(), }); assert_eq!(inner.checked_out(), 1); - let banned = inner.maybe_check_in(server, Instant::now()); - assert!(banned); + let result = inner.maybe_check_in(server, Instant::now(), BackendCounts::default()); + assert!(result.banned); assert_eq!(inner.ban.unwrap().reason, Error::ServerError); assert!(inner.taken.is_empty()); inner.ban = None; inner.config.max = 5; - inner.waiting.push_back(Request::default()); + inner.waiting.push_back(Waiter { + request: Request::default(), + tx: channel().0, + }); assert_eq!(inner.idle(), 1); assert!(!inner.should_create()); @@ -436,12 +516,12 @@ mod test { assert!(inner.should_create()); - inner.conns.push_back(Server::default()); - inner.conns.push_back(Server::default()); + inner.conns.push(Box::new(Server::default())); + inner.conns.push(Box::new(Server::default())); assert!(!inner.should_create()); // Close idle connections. - inner.config.idle_timeout = 5_000; // 5 seconds. + inner.config.idle_timeout = Duration::from_millis(5_000); // 5 seconds. inner.close_idle(Instant::now()); assert_eq!(inner.idle(), inner.config.max); // Didn't close any. for _ in 0..10 { @@ -453,7 +533,7 @@ mod test { assert_eq!(inner.idle(), inner.config.min); // Close old connections. - inner.config.max_age = 60_000; + inner.config.max_age = Duration::from_millis(60_000); inner.close_old(Instant::now() + Duration::from_secs(59)); assert_eq!(inner.idle(), 1); inner.close_old(Instant::now() + Duration::from_secs(61)); @@ -462,15 +542,19 @@ mod test { assert!(inner.should_create()); assert_eq!(inner.total(), 0); - inner.taken.push(Mapping::default()); + inner.taken.take(&Mapping::default()); assert_eq!(inner.total(), 1); inner.taken.clear(); assert_eq!(inner.total(), 0); - let server = Server::default(); - let banned = inner.maybe_check_in(server, Instant::now() + Duration::from_secs(61)); + let server = Box::new(Server::default()); + let result = inner.maybe_check_in( + server, + Instant::now() + Duration::from_secs(61), + BackendCounts::default(), + ); - assert!(!banned); + assert!(!result.banned); // Not checked in because of max age. assert_eq!(inner.total(), 0); } diff --git a/pgdog/src/backend/pool/mod.rs b/pgdog/src/backend/pool/mod.rs index cb81dde3..95ec10df 100644 --- a/pgdog/src/backend/pool/mod.rs +++ b/pgdog/src/backend/pool/mod.rs @@ -20,6 +20,7 @@ pub mod request; pub mod shard; pub mod state; pub mod stats; +pub mod taken; pub mod waiting; pub use address::Address; @@ -42,7 +43,8 @@ use ban::Ban; use comms::Comms; use inner::Inner; use mapping::Mapping; -use waiting::Waiting; +use taken::Taken; +use waiting::{Waiter, Waiting}; #[cfg(test)] pub mod test; diff --git a/pgdog/src/backend/pool/monitor.rs b/pgdog/src/backend/pool/monitor.rs index 1fa82361..25b93ac0 100644 --- a/pgdog/src/backend/pool/monitor.rs +++ b/pgdog/src/backend/pool/monitor.rs @@ -32,12 +32,12 @@ //! connections back to the idle pool in that amount of time, and new connections are no longer needed even //! if clients requested ones to be created ~100ms ago. -use std::time::{Duration, Instant}; +use std::time::Duration; use super::{Error, Guard, Healtcheck, Oids, Pool, Request}; use crate::backend::Server; -use tokio::time::{interval, sleep, timeout}; +use tokio::time::{interval, sleep, timeout, Instant}; use tokio::{select, task::spawn}; use tracing::info; @@ -99,17 +99,20 @@ impl Monitor { // connections are available. _ = comms.request.notified() => { let ( - idle, should_create, connect_timeout, online, ) = { - let guard = self.pool.lock(); + let mut guard = self.pool.lock(); + let online = guard.online; + + if !online { + guard.close_waiters(Error::Offline); + } ( - guard.idle(), guard.should_create(), - guard.config().connect_timeout(), + guard.config().connect_timeout, guard.online, ) }; @@ -118,19 +121,9 @@ impl Monitor { break; } - if idle > 0 { - comms.ready.notify_waiters(); - } - if should_create { - self.pool.lock().creating(); let ok = self.replenish(connect_timeout).await; - if ok { - // Notify all clients we have a connection - // available. - self.pool.lock().created(); - comms.ready.notify_waiters(); - } else { + if !ok { self.pool.ban(Error::ServerError); } } @@ -207,9 +200,17 @@ impl Monitor { let mut guard = pool.lock(); if !guard.online { + guard.close_waiters(Error::Offline); break; } + // If a client is waiting already, + // create it a connection. + if guard.should_create() { + comms.request.notify_one(); + } + + // Don't perform any additional maintenance tasks. if guard.paused { continue; } @@ -218,10 +219,6 @@ impl Monitor { guard.close_old(now); let unbanned = guard.check_ban(now); - if guard.should_create() { - comms.request.notify_one(); - } - if unbanned { info!("pool unbanned due to maintenance [{}]", pool.addr()); } @@ -242,7 +239,10 @@ impl Monitor { match timeout(connect_timeout, Server::connect(self.pool.addr(), options)).await { Ok(Ok(conn)) => { ok = true; - self.pool.lock().put(conn); + let server = Box::new(conn); + + let mut guard = self.pool.lock(); + guard.put(server); } Ok(Err(err)) => { @@ -280,16 +280,16 @@ impl Monitor { } ( guard.take(&Request::default()), - guard.config.healthcheck_timeout(), - guard.config.connect_timeout(), + guard.config.healthcheck_timeout, + guard.config.connect_timeout, ) }; // Have an idle connection, use that for the healthcheck. if let Some(conn) = conn { Healtcheck::mandatory( - &mut Guard::new(pool.clone(), conn), - pool.clone(), + &mut Guard::new(pool.clone(), conn, Instant::now()), + pool, healthcheck_timeout, ) .healthcheck() @@ -306,7 +306,7 @@ impl Monitor { .await { Ok(Ok(mut server)) => { - Healtcheck::mandatory(&mut server, pool.clone(), healthcheck_timeout) + Healtcheck::mandatory(&mut server, pool, healthcheck_timeout) .healthcheck() .await? } diff --git a/pgdog/src/backend/pool/pool_impl.rs b/pgdog/src/backend/pool/pool_impl.rs index 1a5c5627..3ebc21bb 100644 --- a/pgdog/src/backend/pool/pool_impl.rs +++ b/pgdog/src/backend/pool/pool_impl.rs @@ -2,18 +2,19 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; -use std::time::{Duration, Instant}; +use std::time::Duration; use once_cell::sync::Lazy; use parking_lot::{lock_api::MutexGuard, Mutex, RawMutex}; -use tokio::select; -use tokio::time::sleep; +use tokio::time::Instant; use tracing::{error, info}; use crate::backend::{Server, ServerOptions}; +use crate::config::PoolerMode; use crate::net::messages::BackendKeyData; use crate::net::Parameter; +use super::inner::CheckInResult; use super::{ Address, Comms, Config, Error, Guard, Healtcheck, Inner, Monitor, Oids, PoolConfig, Request, State, Waiting, @@ -25,27 +26,24 @@ fn next_pool_id() -> u64 { } /// Connection pool. +#[derive(Clone)] pub struct Pool { - inner: Arc>, - comms: Arc, - addr: Address, - id: u64, + inner: Arc, } -impl std::fmt::Debug for Pool { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Pool").field("addr", &self.addr).finish() - } +pub(crate) struct InnerSync { + pub(super) comms: Comms, + pub(super) addr: Address, + pub(super) inner: Mutex, + pub(super) id: u64, + pub(super) config: Config, } -impl Clone for Pool { - fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - comms: self.comms.clone(), - addr: self.addr.clone(), - id: self.id, - } +impl std::fmt::Debug for Pool { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Pool") + .field("addr", &self.inner.addr) + .finish() } } @@ -54,13 +52,20 @@ impl Pool { pub fn new(config: &PoolConfig) -> Self { let id = next_pool_id(); Self { - inner: Arc::new(Mutex::new(Inner::new(config.config, id))), - comms: Arc::new(Comms::new()), - addr: config.address.clone(), - id, + inner: Arc::new(InnerSync { + comms: Comms::new(), + addr: config.address.clone(), + inner: Mutex::new(Inner::new(config.config, id)), + id, + config: config.config, + }), } } + pub(crate) fn inner(&self) -> &InnerSync { + &self.inner + } + /// Launch the maintenance loop, bringing the pool online. pub fn launch(&self) { let mut guard = self.lock(); @@ -79,79 +84,73 @@ impl Pool { } /// Get a connection from the pool. - async fn get_internal(&self, request: &Request, mut unban: bool) -> Result { - loop { - // Fast path, idle connection probably available. - let (checkout_timeout, healthcheck_timeout, healthcheck_interval, server) = { - let elapsed = request.created_at.elapsed(); // Before the lock! - let mut guard = self.lock(); - - if !guard.online { - return Err(Error::Offline); - } - - // Try this only once. If the pool still - // has an error after a checkout attempt, - // return error. - if unban { - unban = false; - guard.maybe_unban(); - } - - if guard.banned() { - return Err(Error::Banned); - } - - let conn = guard - .take(request) - .map(|server| Guard::new(self.clone(), server)); - - if conn.is_some() { - guard.stats.counts.wait_time += elapsed.as_micros(); - guard.stats.counts.server_assignment_count += 1; - } - - ( - if guard.paused { - Duration::MAX // Wait forever if the pool is paused. - } else { - guard.config.checkout_timeout() - }, - guard.config.healthcheck_timeout(), - guard.config.healthcheck_interval(), - conn, - ) - }; - - if let Some(server) = server { - return self - .maybe_healthcheck(server, healthcheck_timeout, healthcheck_interval) - .await; + async fn get_internal(&self, request: &Request, unban: bool) -> Result { + let pool = self.clone(); + + // Fast path, idle connection probably available. + let (server, granted_at, paused) = { + // Ask for time before we acquire the lock + // and only if we actually waited for a connection. + let granted_at = request.created_at; + let elapsed = granted_at.saturating_duration_since(request.created_at); + let mut guard = self.lock(); + + if !guard.online { + return Err(Error::Offline); } - // Slow path, pool is empty, will create new connection - // or wait for one to be returned if the pool is maxed out. - self.comms().request.notify_one(); - let _waiting = Waiting::new(self.clone(), request); - - select! { - // A connection may be available. - _ = self.comms().ready.notified() => { - let waited_for = request.created_at.elapsed(); - if waited_for >= checkout_timeout { - return Err(Error::CheckoutTimeout); - } - continue; - } - - // Waited too long, return an error. - _ = sleep(checkout_timeout) => { - self.lock() - .maybe_ban(Instant::now(), Error::CheckoutTimeout); - return Err(Error::CheckoutTimeout); - } + // Try this only once. If the pool still + // has an error after a checkout attempt, + // return error. + if unban && guard.banned() { + guard.maybe_unban(); + } + + if guard.banned() { + return Err(Error::Banned); } + + let conn = guard.take(request); + + if conn.is_some() { + guard.stats.counts.wait_time += elapsed; + guard.stats.counts.server_assignment_count += 1; + } + + (conn, granted_at, guard.paused) + }; + + if paused { + self.comms().ready.notified().await; } + + let (server, granted_at) = if let Some(mut server) = server { + ( + Guard::new( + pool, + { + server.set_pooler_mode(self.inner.config.pooler_mode); + server + }, + granted_at, + ), + granted_at, + ) + } else { + // Slow path, pool is empty, will create new connection + // or wait for one to be returned if the pool is maxed out. + let waiting = Waiting::new(pool, request)?; + waiting.wait().await? + }; + + return self + .maybe_healthcheck( + server, + self.inner.config.healthcheck_timeout, + self.inner.config.healthcheck_interval, + granted_at, + ) + .await; } /// Perform a healtcheck on the connection if one is needed. @@ -160,12 +159,14 @@ impl Pool { mut conn: Guard, healthcheck_timeout: Duration, healthcheck_interval: Duration, + now: Instant, ) -> Result { let mut healthcheck = Healtcheck::conditional( &mut conn, - self.clone(), + self, healthcheck_interval, healthcheck_timeout, + now, ); if let Err(err) = healthcheck.healthcheck().await { @@ -186,14 +187,21 @@ impl Pool { } /// Check the connection back into the pool. - pub(super) fn checkin(&self, server: Server) { - // Ask for the time before locking. - // This can take some time on some systems, e.g. EC2. - let now = Instant::now(); + pub(super) fn checkin(&self, mut server: Box) { + // Server is checked in right after transaction finished + // in transaction mode but can be checked in anytime in session mode. + let now = if server.pooler_mode() == &PoolerMode::Session { + Instant::now() + } else { + server.stats().last_used + }; + + let counts = server.stats_mut().reset_last_checkout(); // Check everything and maybe check the connection // into the idle pool. - let banned = self.lock().maybe_check_in(server, now); + let CheckInResult { banned, replenish } = + { self.lock().maybe_check_in(server, now, counts) }; if banned { error!( @@ -201,13 +209,13 @@ impl Pool { Error::ServerError, self.addr() ); - // Tell everyone to stop waiting, this pool is broken. - self.comms().ready.notify_waiters(); } - // Notify clients that a connection may be available - // or at least they should request a new one from the pool again. - self.comms().ready.notify_one(); + // Notify maintenance that we need a new connection because + // the one we tried to check in was broken. + if replenish { + self.comms().request.notify_one(); + } } /// Server connection used by the client. @@ -242,7 +250,6 @@ impl Pool { if banned { error!("pool banned explicitly: {} [{}]", reason, self.addr()); - self.comms().ready.notify_waiters(); } } @@ -256,7 +263,7 @@ impl Pool { /// Connection pool unique identifier. pub(crate) fn id(&self) -> u64 { - self.id + self.inner.id } /// Take connections from the pool and tell all idle ones to be returned @@ -265,7 +272,7 @@ impl Pool { /// This shuts down the pool. pub(crate) fn move_conns_to(&self, destination: &Pool) { // Ensure no deadlock. - assert!(self.id != destination.id()); + assert!(self.inner.id != destination.id()); { let mut from_guard = self.lock(); @@ -313,6 +320,7 @@ impl Pool { guard.online = false; guard.dump_idle(); + guard.close_waiters(Error::Offline); self.comms().shutdown.notify_waiters(); self.comms().ready.notify_waiters(); } @@ -320,19 +328,19 @@ impl Pool { /// Pool exclusive lock. #[inline] pub(super) fn lock(&self) -> MutexGuard<'_, RawMutex, Inner> { - self.inner.lock() + self.inner.inner.lock() } /// Internal notifications. #[inline] pub(super) fn comms(&self) -> &Comms { - &self.comms + &self.inner.comms } /// Pool address. #[inline] pub fn addr(&self) -> &Address { - &self.addr + &self.inner.addr } /// Get startup parameters for new server connections. @@ -348,12 +356,12 @@ impl Pool { }, ]; - let config = *self.lock().config(); + let config = self.inner.config; if let Some(statement_timeout) = config.statement_timeout { params.push(Parameter { name: "statement_timeout".into(), - value: statement_timeout.to_string(), + value: statement_timeout.as_millis().to_string(), }); } @@ -364,6 +372,13 @@ impl Pool { }); } + if config.read_only { + params.push(Parameter { + name: "default_transaction_read_only".into(), + value: "on".into(), + }); + } + ServerOptions { params } } @@ -372,10 +387,9 @@ impl Pool { State::get(self) } - /// Update pool configuration. - /// - /// This takes effect immediately. - pub fn update_config(&self, config: Config) { + /// Update pool configuration used in internals. + #[cfg(test)] + pub(crate) fn update_config(&self, config: Config) { self.lock().config = config; } diff --git a/pgdog/src/backend/pool/replicas.rs b/pgdog/src/backend/pool/replicas.rs index da7ab2c2..2e0e2f54 100644 --- a/pgdog/src/backend/pool/replicas.rs +++ b/pgdog/src/backend/pool/replicas.rs @@ -112,53 +112,51 @@ impl Replicas { request: &Request, primary: &Option, ) -> Result { - let mut candidates = self - .pools - .iter() - .map(|pool| (pool.banned(), pool)) - .collect::>(); - - if let Some(primary) = primary { - candidates.push((primary.banned(), primary)); - } + let mut unbanned = false; + loop { + let mut candidates = self.pools.iter().collect::>(); - match self.lb_strategy { - LoadBalancingStrategy::Random => candidates.shuffle(&mut rand::thread_rng()), - LoadBalancingStrategy::RoundRobin => { - let first = self.round_robin.fetch_add(1, Ordering::Relaxed) % candidates.len(); - let mut reshuffled = vec![]; - reshuffled.extend_from_slice(&candidates[first..]); - reshuffled.extend_from_slice(&candidates[..first]); - candidates = reshuffled; + if let Some(primary) = primary { + candidates.push(primary); } - LoadBalancingStrategy::LeastActiveConnections => { - candidates.sort_by_cached_key(|(_, pool)| pool.lock().idle()); - } - } - - // All replicas are banned, unban everyone. - let banned = candidates.iter().all(|(banned, _)| *banned); - let mut unbanned = false; - if banned { - candidates - .iter() - .for_each(|(_, candidate)| candidate.unban()); - unbanned = true; - } - for (banned, candidate) in candidates { - if banned && !unbanned { - continue; + match self.lb_strategy { + LoadBalancingStrategy::Random => candidates.shuffle(&mut rand::thread_rng()), + LoadBalancingStrategy::RoundRobin => { + let first = self.round_robin.fetch_add(1, Ordering::Relaxed) % candidates.len(); + let mut reshuffled = vec![]; + reshuffled.extend_from_slice(&candidates[first..]); + reshuffled.extend_from_slice(&candidates[..first]); + candidates = reshuffled; + } + LoadBalancingStrategy::LeastActiveConnections => { + candidates.sort_by_cached_key(|pool| pool.lock().idle()); + } } - match candidate.get(request).await { - Ok(conn) => return Ok(conn), - Err(Error::Offline) => continue, - Err(Error::Banned) => continue, - Err(err) => { - error!("{} [{}]", err, candidate.addr()); + let mut banned = 0; + + for candidate in &candidates { + match candidate.get(request).await { + Ok(conn) => return Ok(conn), + Err(Error::Offline) => continue, + Err(Error::Banned) => { + banned += 1; + continue; + } + Err(err) => { + error!("{} [{}]", err, candidate.addr()); + } } } + + // All replicas are banned, unban everyone. + if banned == candidates.len() && !unbanned { + candidates.iter().for_each(|candidate| candidate.unban()); + unbanned = true; + } else { + break; + } } Err(Error::AllReplicasDown) diff --git a/pgdog/src/backend/pool/request.rs b/pgdog/src/backend/pool/request.rs index 7dee1f7e..284f11cb 100644 --- a/pgdog/src/backend/pool/request.rs +++ b/pgdog/src/backend/pool/request.rs @@ -1,9 +1,9 @@ -use std::time::Instant; +use tokio::time::Instant; use crate::net::messages::BackendKeyData; /// Connection request. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Copy)] pub struct Request { pub id: BackendKeyData, pub created_at: Instant, diff --git a/pgdog/src/backend/pool/state.rs b/pgdog/src/backend/pool/state.rs index f93e2b97..c3112830 100644 --- a/pgdog/src/backend/pool/state.rs +++ b/pgdog/src/backend/pool/state.rs @@ -1,6 +1,7 @@ use std::time::Duration; use crate::config::PoolerMode; +use tokio::time::Instant; use super::{Ban, Config, Pool, Stats}; @@ -30,6 +31,8 @@ pub struct State { pub errors: usize, /// Out of sync pub out_of_sync: usize, + /// Re-synced servers. + pub re_synced: usize, /// Statistics pub stats: Stats, /// Max wait. @@ -40,6 +43,7 @@ pub struct State { impl State { pub(super) fn get(pool: &Pool) -> Self { + let now = Instant::now(); let guard = pool.lock(); State { @@ -55,12 +59,13 @@ impl State { banned: guard.ban.is_some(), errors: guard.errors, out_of_sync: guard.out_of_sync, + re_synced: guard.re_synced, stats: guard.stats, maxwait: guard .waiting .iter() .next() - .map(|req| req.created_at.elapsed()) + .map(|req| now.duration_since(req.request.created_at)) .unwrap_or(Duration::ZERO), pooler_mode: guard.config().pooler_mode, } diff --git a/pgdog/src/backend/pool/stats.rs b/pgdog/src/backend/pool/stats.rs index e08d990d..9d109cca 100644 --- a/pgdog/src/backend/pool/stats.rs +++ b/pgdog/src/backend/pool/stats.rs @@ -1,13 +1,13 @@ //! Pool stats. +use crate::backend::stats::Counts as BackendCounts; + use std::{ iter::Sum, ops::{Add, Div, Sub}, time::Duration, }; -type Millis = u128; - #[derive(Debug, Clone, Default, Copy)] pub struct Counts { pub xact_count: usize, @@ -15,11 +15,12 @@ pub struct Counts { pub server_assignment_count: usize, pub received: usize, pub sent: usize, - pub xact_time: Millis, - pub query_time: Millis, - pub wait_time: Millis, + pub xact_time: Duration, + pub query_time: Duration, + pub wait_time: Duration, pub parse_count: usize, pub bind_count: usize, + pub rollbacks: usize, } impl Sub for Counts { @@ -37,8 +38,9 @@ impl Sub for Counts { xact_time: self.xact_time.saturating_sub(rhs.xact_time), query_time: self.query_time.saturating_sub(rhs.query_time), wait_time: self.wait_time.saturating_sub(rhs.wait_time), - parse_count: self.parse_count.saturating_add(rhs.parse_count), - bind_count: self.parse_count.saturating_add(rhs.bind_count), + parse_count: self.parse_count.saturating_sub(rhs.parse_count), + bind_count: self.parse_count.saturating_sub(rhs.bind_count), + rollbacks: self.rollbacks.saturating_sub(rhs.rollbacks), } } } @@ -53,32 +55,32 @@ impl Div for Counts { server_assignment_count: self.server_assignment_count.saturating_div(rhs), received: self.received.saturating_div(rhs), sent: self.sent.saturating_div(rhs), - xact_time: self.xact_time.saturating_div(rhs as u128), - query_time: self.query_time.saturating_div(rhs as u128), - wait_time: self.wait_time.saturating_div(rhs as u128), + xact_time: self.xact_time.checked_div(rhs as u32).unwrap_or_default(), + query_time: self.query_time.checked_div(rhs as u32).unwrap_or_default(), + wait_time: self.wait_time.checked_div(rhs as u32).unwrap_or_default(), parse_count: self.parse_count.saturating_div(rhs), bind_count: self.parse_count.saturating_div(rhs), + rollbacks: self.rollbacks.saturating_div(rhs), } } } -impl Add for Counts { +impl Add for Counts { type Output = Counts; - fn add(self, rhs: crate::backend::stats::Counts) -> Self::Output { + fn add(self, rhs: BackendCounts) -> Self::Output { Counts { - xact_count: self.xact_count.saturating_add(rhs.transactions), - query_count: self.query_count.saturating_add(rhs.queries), + xact_count: self.xact_count + rhs.transactions, + query_count: self.query_count + rhs.queries, server_assignment_count: self.server_assignment_count + 1, - received: self.received.saturating_add(rhs.bytes_received), - sent: self.sent.saturating_add(rhs.bytes_sent), - query_time: self.query_time.saturating_add(rhs.query_time.as_millis()), - xact_time: self - .xact_time - .saturating_add(rhs.transaction_time.as_millis()), + received: self.received + rhs.bytes_received, + sent: self.sent + rhs.bytes_sent, + query_time: self.query_time + rhs.query_time, + xact_time: self.xact_time + rhs.transaction_time, wait_time: self.wait_time, - parse_count: self.parse_count.saturating_add(rhs.parse), - bind_count: self.parse_count.saturating_add(rhs.bind), + parse_count: self.parse_count + rhs.parse, + bind_count: self.parse_count + rhs.bind, + rollbacks: self.rollbacks + rhs.rollbacks, } } } @@ -111,6 +113,7 @@ impl Add for Counts { wait_time: self.wait_time.saturating_add(rhs.wait_time), parse_count: self.parse_count.saturating_add(rhs.parse_count), bind_count: self.parse_count.saturating_add(rhs.bind_count), + rollbacks: self.rollbacks.saturating_add(rhs.rollbacks), } } } diff --git a/pgdog/src/backend/pool/taken.rs b/pgdog/src/backend/pool/taken.rs new file mode 100644 index 00000000..0d13e48c --- /dev/null +++ b/pgdog/src/backend/pool/taken.rs @@ -0,0 +1,53 @@ +use fnv::FnvHashMap as HashMap; + +use crate::net::BackendKeyData; + +use super::Mapping; + +#[derive(Default, Clone, Debug)] +pub(super) struct Taken { + client_server: HashMap, + server_client: HashMap, +} + +impl Taken { + #[inline] + pub(super) fn take(&mut self, mapping: &Mapping) { + self.client_server.insert(mapping.client, mapping.server); + self.server_client.insert(mapping.server, mapping.client); + } + + #[inline] + pub(super) fn check_in(&mut self, server: &BackendKeyData) { + let client = self.server_client.remove(server); + if let Some(client) = client { + self.client_server.remove(&client); + } + } + + #[inline] + pub(super) fn len(&self) -> usize { + self.client_server.len() // Both should always be the same length. + } + + #[allow(dead_code)] + pub(super) fn is_empty(&self) -> bool { + self.len() == 0 + } + + #[inline] + pub(super) fn server(&self, client: &BackendKeyData) -> Option { + self.client_server.get(client).cloned() + } + + #[allow(dead_code)] + pub(super) fn client(&self, server: &BackendKeyData) -> Option { + self.server_client.get(server).cloned() + } + + #[cfg(test)] + pub(super) fn clear(&mut self) { + self.client_server.clear(); + self.server_client.clear(); + } +} diff --git a/pgdog/src/backend/pool/test/mod.rs b/pgdog/src/backend/pool/test/mod.rs index eee9e642..8ecbf082 100644 --- a/pgdog/src/backend/pool/test/mod.rs +++ b/pgdog/src/backend/pool/test/mod.rs @@ -2,13 +2,17 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; -use std::time::Duration; +use std::time::{Duration, Instant}; use rand::Rng; use tokio::task::yield_now; use tokio::time::{sleep, timeout}; use tokio_util::task::TaskTracker; +use crate::backend::ProtocolMessage; +use crate::net::Query; +use crate::state::State; + use super::*; mod replica; @@ -42,7 +46,7 @@ async fn test_pool_checkout() { let conn = pool.get(&Request::default()).await.unwrap(); let id = *(conn.id()); - assert!(conn.in_sync()); + assert!(conn.done()); assert!(conn.done()); assert!(!conn.in_transaction()); assert!(!conn.error()); @@ -121,7 +125,7 @@ async fn test_concurrency_with_gas() { async fn test_bans() { let pool = pool(); let mut config = *pool.lock().config(); - config.checkout_timeout = 100; + config.checkout_timeout = Duration::from_millis(100); pool.update_config(config); pool.ban(Error::CheckoutTimeout); @@ -151,7 +155,7 @@ async fn test_pause() { let pool = pool(); let tracker = TaskTracker::new(); let config = Config { - checkout_timeout: 1_000, + checkout_timeout: Duration::from_millis(1_000), max: 1, ..Default::default() }; @@ -213,3 +217,75 @@ async fn test_pause() { tracker.wait().await; assert!(!didnt_work.load(Ordering::Relaxed)); } + +// Proof that the mutex is working well. +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +#[ignore] +async fn test_benchmark_pool() { + let counts = 500_000; + let workers = 4; + + let pool = pool(); + + // Prewarm + let request = Request::default(); + drop(pool.get(&request).await.unwrap()); + + let mut handles = Vec::with_capacity(2); + let start = Instant::now(); + + for _ in 0..workers { + let pool = pool.clone(); + let handle = tokio::spawn(async move { + for _ in 0..counts { + let conn = pool.get(&request).await.unwrap(); + conn.addr(); + drop(conn); + } + }); + handles.push(handle); + } + for handle in handles { + handle.await.unwrap(); + } + let duration = start.elapsed(); + println!("bench: {}ms", duration.as_millis()); +} + +#[tokio::test] +async fn test_incomplete_request_recovery() { + crate::logger(); + + let pool = pool(); + + for query in ["SELECT 1", "BEGIN"] { + let mut conn = pool.get(&Request::default()).await.unwrap(); + + conn.send(&vec![ProtocolMessage::from(Query::new(query))].into()) + .await + .unwrap(); + drop(conn); // Drop the connection to simulating client dying. + + sleep(Duration::from_millis(500)).await; + let state = pool.state(); + let out_of_sync = state.out_of_sync; + assert_eq!(out_of_sync, 0); + assert_eq!(state.idle, 1); + if query == "BEGIN" { + assert_eq!(state.stats.counts.rollbacks, 1); + } else { + assert_eq!(state.stats.counts.rollbacks, 0); + } + } +} + +#[tokio::test] +async fn test_force_close() { + let pool = pool(); + let mut conn = pool.get(&Request::default()).await.unwrap(); + conn.execute("BEGIN").await.unwrap(); + assert!(conn.in_transaction()); + conn.stats_mut().state(State::ForceClose); + drop(conn); + assert_eq!(pool.lock().force_close, 1); +} diff --git a/pgdog/src/backend/pool/test/replica.rs b/pgdog/src/backend/pool/test/replica.rs index 49954bd1..6bd082d9 100644 --- a/pgdog/src/backend/pool/test/replica.rs +++ b/pgdog/src/backend/pool/test/replica.rs @@ -15,7 +15,7 @@ fn replicas() -> Replicas { }, config: Config { max: 1, - checkout_timeout: 1000, + checkout_timeout: Duration::from_millis(1000), ..Default::default() }, }; diff --git a/pgdog/src/backend/pool/waiting.rs b/pgdog/src/backend/pool/waiting.rs index 35bdd183..e3477f69 100644 --- a/pgdog/src/backend/pool/waiting.rs +++ b/pgdog/src/backend/pool/waiting.rs @@ -1,21 +1,66 @@ -use super::{Pool, Request}; +use crate::backend::Server; + +use super::{Error, Guard, Pool, Request}; +use tokio::{ + sync::oneshot::*, + time::{timeout, Instant}, +}; pub(super) struct Waiting { pool: Pool, + rx: Receiver, Error>>, + request: Request, } impl Waiting { - pub(super) fn new(pool: Pool, request: &Request) -> Self { + pub(super) fn new(pool: Pool, request: &Request) -> Result { + let request = *request; + let (tx, rx) = channel(); + { - let mut inner = pool.lock(); - inner.waiting.push_back(request.clone()); + let mut guard = pool.lock(); + if !guard.online { + return Err(Error::Offline); + } + guard.waiting.push_back(Waiter { request, tx }) } - Self { pool } + + // Tell maintenance we are in line waiting for a connection. + pool.comms().request.notify_one(); + + Ok(Self { pool, rx, request }) } -} -impl Drop for Waiting { - fn drop(&mut self) { - self.pool.lock().waiting.pop_front(); + pub(super) async fn wait(self) -> Result<(Guard, Instant), Error> { + let checkout_timeout = self.pool.inner().config.checkout_timeout; + let server = timeout(checkout_timeout, self.rx).await; + + let now = Instant::now(); + match server { + Ok(Ok(server)) => { + let server = server?; + Ok((Guard::new(self.pool.clone(), server, now), now)) + } + + Err(_err) => { + let mut guard = self.pool.lock(); + if !guard.banned() { + guard.maybe_ban(now, Error::CheckoutTimeout); + } + guard.remove_waiter(&self.request.id); + Err(Error::CheckoutTimeout) + } + + // Should not be possible. + // This means someone removed my waiter from the wait queue, + // indicating a bug in the pool. + Ok(Err(_)) => Err(Error::CheckoutTimeout), + } } } + +#[derive(Debug)] +pub(super) struct Waiter { + pub(super) request: Request, + pub(super) tx: Sender, Error>>, +} diff --git a/pgdog/src/backend/prepared_statements.rs b/pgdog/src/backend/prepared_statements.rs index bfff9bf2..51442072 100644 --- a/pgdog/src/backend/prepared_statements.rs +++ b/pgdog/src/backend/prepared_statements.rs @@ -40,7 +40,6 @@ pub struct PreparedStatements { parses: VecDeque, // Describes being executed now on the connection. describes: VecDeque, - enabled: bool, } impl Default for PreparedStatements { @@ -58,32 +57,19 @@ impl PreparedStatements { state: ProtocolState::default(), parses: VecDeque::new(), describes: VecDeque::new(), - enabled: true, } } - pub fn toggle(&mut self, enabled: bool) { - self.enabled = enabled; - } - - pub(crate) fn enabled(&self) -> bool { - self.enabled - } - /// Handle extended protocol message. pub fn handle(&mut self, request: &ProtocolMessage) -> Result { - if !self.enabled { - return Ok(HandleResult::Forward); - } - match request { ProtocolMessage::Bind(bind) => { if !bind.anonymous() { - let message = self.check_prepared(&bind.statement)?; + let message = self.check_prepared(bind.statement())?; match message { Some(message) => { - self.state.add_ignore('1', &bind.statement); - self.prepared(&bind.statement); + self.state.add_ignore('1', bind.statement()); + self.prepared(bind.statement()); self.state.add('2'); return Ok(HandleResult::Prepend(message)); } @@ -99,12 +85,12 @@ impl PreparedStatements { ProtocolMessage::Describe(describe) => { if !describe.anonymous() { - let message = self.check_prepared(&describe.statement)?; + let message = self.check_prepared(describe.statement())?; match message { Some(message) => { - self.state.add_ignore('1', &describe.statement); - self.prepared(&describe.statement); + self.state.add_ignore('1', describe.statement()); + self.prepared(describe.statement()); self.state.add(ExecutionCode::DescriptionOrNothing); // t self.state.add(ExecutionCode::DescriptionOrNothing); // T return Ok(HandleResult::Prepend(message)); @@ -117,7 +103,7 @@ impl PreparedStatements { } } - self.describes.push_back(describe.statement.clone()); + self.describes.push_back(describe.statement().to_string()); } else { self.state.add(ExecutionCode::DescriptionOrNothing); } @@ -170,10 +156,6 @@ impl PreparedStatements { /// Should we forward the message to the client. pub fn forward(&mut self, message: &Message) -> Result { - if !self.enabled { - return Ok(true); - } - let code = message.code(); let action = self.state.action(code)?; diff --git a/pgdog/src/backend/protocol/buffer.rs b/pgdog/src/backend/protocol/buffer.rs deleted file mode 100644 index ff6033e0..00000000 --- a/pgdog/src/backend/protocol/buffer.rs +++ /dev/null @@ -1,12 +0,0 @@ -// use super::Request; - -// #[derive(Debug, Clone, Default)] -// pub struct Buffer { -// requests: Vec, -// } - -// impl From for Buffer { -// fn from(value: crate::frontend::Buffer) -> Self { -// let mut buffer = Buffer::default(); -// } -// } diff --git a/pgdog/src/backend/protocol/mod.rs b/pgdog/src/backend/protocol/mod.rs index c57df69f..15f204fd 100644 --- a/pgdog/src/backend/protocol/mod.rs +++ b/pgdog/src/backend/protocol/mod.rs @@ -1,4 +1,3 @@ -pub mod buffer; pub mod protocol_message; pub mod state; diff --git a/pgdog/src/backend/reload_notify.rs b/pgdog/src/backend/reload_notify.rs new file mode 100644 index 00000000..69b65c4b --- /dev/null +++ b/pgdog/src/backend/reload_notify.rs @@ -0,0 +1,33 @@ +use std::sync::atomic::{AtomicBool, Ordering}; + +use once_cell::sync::Lazy; +use tokio::sync::{futures::Notified, Notify}; + +static RELOAD_NOTIFY: Lazy = Lazy::new(|| ReloadNotify { + notify: Notify::new(), + ready: AtomicBool::new(true), +}); + +pub(crate) fn ready() -> Option> { + let notified = RELOAD_NOTIFY.notify.notified(); + if RELOAD_NOTIFY.ready.load(Ordering::Relaxed) { + None + } else { + Some(notified) + } +} + +pub(super) fn started() { + RELOAD_NOTIFY.ready.store(false, Ordering::Relaxed); +} + +pub(super) fn done() { + RELOAD_NOTIFY.ready.store(true, Ordering::Relaxed); + RELOAD_NOTIFY.notify.notify_waiters(); +} + +#[derive(Debug)] +struct ReloadNotify { + notify: Notify, + ready: AtomicBool, +} diff --git a/pgdog/src/backend/replication/sharded_tables.rs b/pgdog/src/backend/replication/sharded_tables.rs index 23743075..0d4b1ea6 100644 --- a/pgdog/src/backend/replication/sharded_tables.rs +++ b/pgdog/src/backend/replication/sharded_tables.rs @@ -21,7 +21,7 @@ impl From<&[ShardedTable]> for ShardedTables { impl ShardedTables { pub fn new(tables: Vec, omnisharded_tables: Vec, dry_run: bool) -> Self { Self { - tables: Arc::new(tables.iter().map(|t| t.clone()).collect()), + tables: Arc::new(tables.to_vec()), omnisharded: Arc::new(omnisharded_tables.into_iter().collect()), dry_run, } diff --git a/pgdog/src/backend/schema/mod.rs b/pgdog/src/backend/schema/mod.rs index 1bfbba3a..0bed3408 100644 --- a/pgdog/src/backend/schema/mod.rs +++ b/pgdog/src/backend/schema/mod.rs @@ -2,7 +2,8 @@ pub mod columns; pub mod relation; -use std::collections::HashMap; +use std::sync::Arc; +use std::{collections::HashMap, ops::Deref}; use tracing::debug; pub use relation::Relation; @@ -11,10 +12,16 @@ use super::{pool::Request, Cluster, Error, Server}; static SETUP: &str = include_str!("setup.sql"); +#[derive(Debug, Default)] +struct Inner { + search_path: Vec, + relations: HashMap<(String, String), Relation>, +} + /// Load schema from database. #[derive(Debug, Clone, Default)] pub struct Schema { - relations: HashMap<(String, String), Relation>, + inner: Arc, } impl Schema { @@ -31,7 +38,23 @@ impl Schema { }) .collect(); - Ok(Self { relations }) + let search_path = server + .fetch_all::("SHOW search_path") + .await? + .pop() + .unwrap_or(String::from("$user, public")) + .split(",") + .map(|p| p.trim().replace("\"", "")) + .collect(); + + let inner = Inner { + search_path, + relations, + }; + + Ok(Self { + inner: Arc::new(inner), + }) } /// Load schema from primary database. @@ -68,7 +91,7 @@ impl Schema { .iter() .filter(|table| table.schema() != "pgdog") { - let column_match = schema_table.columns.iter().find(|column| { + let column_match = schema_table.columns.values().find(|column| { column.column_name == table.column && column.data_type == "bigint" }); if let Some(column_match) = column_match { @@ -110,12 +133,15 @@ impl Schema { /// Get table by name. pub fn table(&self, name: &str, schema: Option<&str>) -> Option<&Relation> { let schema = schema.unwrap_or("public"); - self.relations.get(&(name.to_string(), schema.to_string())) + self.inner + .relations + .get(&(name.to_string(), schema.to_string())) } /// Get all indices. pub fn tables(&self) -> Vec<&Relation> { - self.relations + self.inner + .relations .values() .filter(|value| value.is_table()) .collect() @@ -123,11 +149,25 @@ impl Schema { /// Get all sequences. pub fn sequences(&self) -> Vec<&Relation> { - self.relations + self.inner + .relations .values() .filter(|value| value.is_sequence()) .collect() } + + /// Get search path components. + pub fn search_path(&self) -> &[String] { + &self.inner.search_path + } +} + +impl Deref for Schema { + type Target = HashMap<(String, String), Relation>; + + fn deref(&self) -> &Self::Target { + &self.inner.relations + } } #[cfg(test)] diff --git a/pgdog/src/backend/schema/relation.rs b/pgdog/src/backend/schema/relation.rs index 5b0cde5d..ac3b5dc4 100644 --- a/pgdog/src/backend/schema/relation.rs +++ b/pgdog/src/backend/schema/relation.rs @@ -20,7 +20,7 @@ pub struct Relation { pub size: usize, pub description: String, pub oid: i32, - pub columns: Vec, + pub columns: HashMap, } impl From for Relation { @@ -35,7 +35,7 @@ impl From for Relation { size: value.get_int(6, true).unwrap_or_default() as usize, description: value.get_text(7).unwrap_or_default(), oid: value.get::(8, Format::Text).unwrap_or_default(), - columns: vec![], + columns: HashMap::new(), } } } @@ -57,7 +57,11 @@ impl Relation { let columns = Column::load(server).await?; for column in columns { if let Some(relation) = relations.get_mut(&column.0) { - relation.columns = column.1; + relation.columns = column + .1 + .into_iter() + .map(|c| (c.column_name.clone(), c)) + .collect(); } } @@ -87,6 +91,11 @@ impl Relation { pub fn is_sequence(&self) -> bool { self.type_ == "sequence" } + + /// Columns by name. + pub fn columns(&self) -> &HashMap { + &self.columns + } } #[cfg(test)] diff --git a/pgdog/src/backend/server.rs b/pgdog/src/backend/server.rs index c5675369..92aecabe 100644 --- a/pgdog/src/backend/server.rs +++ b/pgdog/src/backend/server.rs @@ -1,5 +1,5 @@ //! PostgreSQL server connection. -use std::time::{Duration, Instant}; +use std::time::Duration; use bytes::{BufMut, BytesMut}; use rustls_pki_types::ServerName; @@ -7,6 +7,7 @@ use tokio::{ io::{AsyncReadExt, AsyncWriteExt}, net::TcpStream, spawn, + time::Instant, }; use tracing::{debug, error, info, trace, warn}; @@ -14,17 +15,24 @@ use super::{ pool::Address, prepared_statements::HandleResult, Error, PreparedStatements, ProtocolMessage, ServerOptions, Stats, }; -use crate::net::{ - messages::{DataRow, NoticeResponse}, - parameter::Parameters, - tls::connector, - CommandComplete, Stream, -}; use crate::{ auth::{md5, scram::Client}, - net::messages::{ - hello::SslReply, Authentication, BackendKeyData, ErrorResponse, FromBytes, Message, - ParameterStatus, Password, Protocol, Query, ReadyForQuery, Startup, Terminate, ToBytes, + frontend::Buffer, + net::{ + messages::{ + hello::SslReply, Authentication, BackendKeyData, ErrorResponse, FromBytes, Message, + ParameterStatus, Password, Protocol, Query, ReadyForQuery, Startup, Terminate, ToBytes, + }, + Parameter, Sync, + }, +}; +use crate::{ + config::PoolerMode, + net::{ + messages::{DataRow, NoticeResponse}, + parameter::Parameters, + tls::connector, + CommandComplete, Stream, }, }; use crate::{net::tweak, state::State}; @@ -36,14 +44,18 @@ pub struct Server { stream: Option, id: BackendKeyData, params: Parameters, - options: ServerOptions, changed_params: Parameters, + client_params: Parameters, stats: Stats, prepared_statements: PreparedStatements, dirty: bool, streaming: bool, schema_changed: bool, sync_prepared: bool, + in_transaction: bool, + re_synced: bool, + pooler_mode: PoolerMode, + stream_buffer: BytesMut, } impl Server { @@ -127,7 +139,7 @@ impl Server { } } - let mut params = Parameters::default(); + let mut params = Vec::new(); let mut key_data: Option = None; loop { @@ -139,7 +151,7 @@ impl Server { // ParameterStatus (B) 'S' => { let parameter = ParameterStatus::from_bytes(message.payload())?; - params.insert(parameter.name, parameter.value); + params.push(Parameter::from(parameter)); } // BackendKeyData (B) 'K' => { @@ -162,6 +174,7 @@ impl Server { } let id = key_data.ok_or(Error::NoBackendKeyData)?; + let params: Parameters = params.into(); info!("new server connection [{}]", addr); @@ -169,15 +182,19 @@ impl Server { addr: addr.clone(), stream: Some(stream), id, - options, + stats: Stats::connect(id, addr, ¶ms), params, changed_params: Parameters::default(), - stats: Stats::connect(id, addr), + client_params: Parameters::default(), prepared_statements: PreparedStatements::new(), dirty: false, streaming: false, schema_changed: false, sync_prepared: false, + in_transaction: false, + re_synced: false, + pooler_mode: PoolerMode::Transaction, + stream_buffer: BytesMut::with_capacity(1024), }) } @@ -199,36 +216,36 @@ impl Server { } /// Send messages to the server and flush the buffer. - pub async fn send(&mut self, messages: Vec>) -> Result<(), Error> { - let timer = Instant::now(); - for message in messages { + pub async fn send(&mut self, messages: &Buffer) -> Result<(), Error> { + self.stats.state(State::Active); + + for message in messages.iter() { self.send_one(message).await?; } self.flush().await?; - trace!( - "request flushed to server [{:.4}ms]", - timer.elapsed().as_secs_f64() * 1000.0 - ); + + self.stats.state(State::ReceivingData); + Ok(()) } /// Send one message to the server but don't flush the buffer, /// accelerating bulk transfers. - pub async fn send_one(&mut self, message: impl Into) -> Result<(), Error> { + pub async fn send_one(&mut self, message: &ProtocolMessage) -> Result<(), Error> { self.stats.state(State::Active); - let message: ProtocolMessage = message.into(); - let result = self.prepared_statements.handle(&message)?; + + let result = self.prepared_statements.handle(message)?; let queue = match result { HandleResult::Drop => [None, None], - HandleResult::Prepend(prepare) => [Some(prepare), Some(message)], + HandleResult::Prepend(ref prepare) => [Some(prepare), Some(message)], HandleResult::Forward => [Some(message), None], }; for message in queue.into_iter().flatten() { - trace!("{:#?} → [{}]", message, self.addr()); + trace!(">>> {:?} [{}]", message, self.addr()); - match self.stream().send(&message).await { + match self.stream().send(message).await { Ok(sent) => self.stats.send(sent), Err(err) => { self.stats.state(State::Error); @@ -243,6 +260,7 @@ impl Server { /// Flush all pending messages making sure they are sent to the server immediately. pub async fn flush(&mut self) -> Result<(), Error> { if let Err(err) = self.stream().flush().await { + trace!("😳"); self.stats.state(State::Error); Err(err.into()) } else { @@ -256,7 +274,13 @@ impl Server { if let Some(message) = self.prepared_statements.state_mut().get_simulated() { return Ok(message); } - match self.stream().read().await { + match self + .stream + .as_mut() + .unwrap() + .read_buf(&mut self.stream_buffer) + .await + { Ok(message) => { let message = message.stream(self.streaming).backend(); match self.prepared_statements.forward(&message) { @@ -294,8 +318,14 @@ impl Server { let rfq = ReadyForQuery::from_bytes(message.payload())?; match rfq.status { - 'I' => self.stats.transaction(now), - 'T' => self.stats.state(State::IdleInTransaction), + 'I' => { + self.in_transaction = false; + self.stats.transaction(now); + } + 'T' => { + self.in_transaction = true; + self.stats.state(State::IdleInTransaction); + } 'E' => self.stats.transaction_error(now), status => { self.stats.state(State::Error); @@ -320,45 +350,52 @@ impl Server { } 'C' => { let cmd = CommandComplete::from_bytes(message.to_bytes()?)?; - match cmd.command.as_str() { + match cmd.command() { "PREPARE" | "DEALLOCATE" => self.sync_prepared = true, + "RESET" => self.client_params.clear(), // Someone reset params, we're gonna need to re-sync. _ => (), } } + 'G' => self.stats.copy_mode(), '1' => self.stats.parse_complete(), '2' => self.stats.bind_complete(), _ => (), } - trace!("{:#?} ← [{}]", message, self.addr()); + trace!("<<< {:?} [{}]", message, self.addr()); Ok(message.backend()) } /// Synchronize parameters between client and server. - pub async fn link_client( - &mut self, - params: &Parameters, - prepared_statements: bool, - ) -> Result { - // Toggle support for prepared statements - // only when client connects to this server. - self.prepared_statements.toggle(prepared_statements); - - let diff = params.merge(&mut self.params); - if diff.changed_params > 0 { - debug!("syncing {} params", diff.changed_params); - self.execute_batch( - &diff - .queries - .iter() - .map(|query| query.query()) - .collect::>(), - ) - .await?; - } + pub async fn link_client(&mut self, params: &Parameters) -> Result { + // Sync application_name parameter + // and update it in the stats. + let default_name = "PgDog"; + let server_name = self + .client_params + .get_default("application_name", default_name); + let client_name = params.get_default("application_name", default_name); + self.stats.link_client(client_name, server_name); + + // Clear any params previously tracked by SET. self.changed_params.clear(); - Ok(diff.changed_params) + + // Compare client and server params. + if !params.identical(&self.client_params) { + debug!("params are different"); + let tracked = params.tracked(); + let mut queries = self.client_params.reset_queries(); + queries.extend(tracked.set_queries()); + if !queries.is_empty() { + debug!("syncing {} params", queries.len()); + self.execute_batch(&queries).await?; + } + self.client_params = tracked; + Ok(queries.len()) + } else { + Ok(0) + } } pub fn changed_params(&self) -> &Parameters { @@ -369,37 +406,37 @@ impl Server { self.changed_params.clear(); } - /// Server sent everything. - #[inline] + /// We can disconnect from this server. + /// + /// There are no more expected messages from the server connection + /// and we haven't started an explicit transaction. pub fn done(&self) -> bool { - if self.prepared_statements.enabled() { - self.prepared_statements.done() && !self.in_transaction() - } else { - matches!(self.stats.state, State::Idle | State::Error) - } + self.prepared_statements.done() && !self.in_transaction() } - #[inline] - pub fn has_more_messages(&self) -> bool { - !matches!( + /// Server can execute a query. + pub fn in_sync(&self) -> bool { + matches!( self.stats.state, State::Idle | State::IdleInTransaction | State::TransactionError - ) || !self.prepared_statements.done() + ) } - /// Server connection is synchronized and can receive more messages. - #[inline] - pub fn in_sync(&self) -> bool { - self.prepared_statements.done() && !self.streaming + /// Server is done executing all queries and is + /// not inside a transaction. + pub fn can_check_in(&self) -> bool { + self.stats.state == State::Idle + } + + /// Server hasn't sent all messages yet. + pub fn has_more_messages(&self) -> bool { + !self.prepared_statements.done() || self.streaming } /// Server is still inside a transaction. #[inline] pub fn in_transaction(&self) -> bool { - matches!( - self.stats.state, - State::IdleInTransaction | State::TransactionError - ) + self.in_transaction } /// The server connection permanently failed. @@ -413,10 +450,22 @@ impl Server { self.schema_changed } + /// Prepared statements changed outside of our pipeline, + /// need to resync from `pg_prepared_statements` view. pub fn sync_prepared(&self) -> bool { self.sync_prepared } + /// Connection was left with an unfinished query. + pub fn needs_drain(&self) -> bool { + !self.in_sync() + } + + /// Close the connection, don't do any recovery. + pub fn force_close(&self) -> bool { + self.stats.state == State::ForceClose + } + /// Server parameters. #[inline] pub fn params(&self) -> &Parameters { @@ -424,21 +473,30 @@ impl Server { } /// Execute a batch of queries and return all results. - pub async fn execute_batch(&mut self, queries: &[&str]) -> Result, Error> { + pub async fn execute_batch(&mut self, queries: &[Query]) -> Result, Error> { if !self.in_sync() { return Err(Error::NotInSync); } + // Empty queries will throw the server out of sync. + if queries.is_empty() { + return Ok(vec![]); + } + #[cfg(debug_assertions)] for query in queries { - debug!("{} [{}]", query, self.addr()); + debug!("{} [{}]", query.query(), self.addr()); } let mut messages = vec![]; - let queries = queries.iter().map(Query::new).collect::>(); + let queries = queries + .iter() + .map(Clone::clone) + .map(ProtocolMessage::Query) + .collect::>(); let expected = queries.len(); - self.send(queries).await?; + self.send(&queries.into()).await?; let mut zs = 0; while zs < expected { @@ -458,13 +516,17 @@ impl Server { } /// Execute a query on the server and return the result. - pub async fn execute(&mut self, query: &str) -> Result, Error> { - debug!("[{}] {} ", self.addr(), query,); + pub async fn execute(&mut self, query: impl Into) -> Result, Error> { + let query = query.into(); + debug!("[{}] {} ", self.addr(), query.query(),); self.execute_batch(&[query]).await } /// Execute query and raise an error if one is returned by PostgreSQL. - pub async fn execute_checked(&mut self, query: &str) -> Result, Error> { + pub async fn execute_checked( + &mut self, + query: impl Into, + ) -> Result, Error> { let messages = self.execute(query).await?; let error = messages.iter().find(|m| m.code() == 'E'); if let Some(error) = error { @@ -476,7 +538,10 @@ impl Server { } /// Execute a query and return all rows. - pub async fn fetch_all>(&mut self, query: &str) -> Result, Error> { + pub async fn fetch_all>( + &mut self, + query: impl Into, + ) -> Result, Error> { let messages = self.execute_checked(query).await?; Ok(messages .into_iter() @@ -508,11 +573,39 @@ impl Server { self.stats.rollback(); } - if !self.in_sync() { + if !self.done() { self.stats.state(State::Error); } } + pub async fn drain(&mut self) { + while self.has_more_messages() { + if self.read().await.is_err() { + self.stats.state(State::Error); + break; + } + } + + if !self.in_sync() { + if self + .send(&vec![ProtocolMessage::Sync(Sync)].into()) + .await + .is_err() + { + self.stats.state(State::Error); + return; + } + while !self.in_sync() { + if self.read().await.is_err() { + self.stats.state(State::Error); + break; + } + } + + self.re_synced = true; + } + } + pub async fn sync_prepared_statements(&mut self) -> Result<(), Error> { let names = self .fetch_all::("SELECT name FROM pg_prepared_statements") @@ -536,7 +629,17 @@ impl Server { #[inline] pub fn reset_params(&mut self) { - self.params = self.options.params.clone().into(); + self.client_params.clear(); + } + + #[inline] + pub fn reset_re_synced(&mut self) { + self.re_synced = false; + } + + #[inline] + pub fn re_synced(&self) -> bool { + self.re_synced } /// Server connection unique identifier. @@ -606,6 +709,16 @@ impl Server { pub fn stats_mut(&mut self) -> &mut Stats { &mut self.stats } + + #[inline] + pub fn set_pooler_mode(&mut self, pooler_mode: PoolerMode) { + self.pooler_mode = pooler_mode; + } + + #[inline] + pub fn pooler_mode(&self) -> &PoolerMode { + &self.pooler_mode + } } impl Drop for Server { @@ -647,14 +760,18 @@ pub mod test { id, params: Parameters::default(), changed_params: Parameters::default(), - options: ServerOptions::default(), - stats: Stats::connect(id, &addr), + client_params: Parameters::default(), + stats: Stats::connect(id, &addr, &Parameters::default()), prepared_statements: super::PreparedStatements::new(), addr, dirty: false, streaming: false, schema_changed: false, sync_prepared: false, + in_transaction: false, + re_synced: false, + pooler_mode: PoolerMode::Transaction, + stream_buffer: BytesMut::with_capacity(1024), } } } @@ -687,7 +804,7 @@ pub mod test { let mut server = test_server().await; for _ in 0..25 { server - .send(vec![ProtocolMessage::from(Query::new("SELECT 1"))]) + .send(&vec![ProtocolMessage::from(Query::new("SELECT 1"))].into()) .await .unwrap(); let msg = server.read().await.unwrap(); @@ -704,7 +821,7 @@ pub mod test { for _ in 0..25 { server - .send(vec![ProtocolMessage::from(Query::new("SELECT 1"))]) + .send(&vec![ProtocolMessage::from(Query::new("SELECT 1"))].into()) .await .unwrap(); } @@ -722,7 +839,7 @@ pub mod test { let mut server = test_server().await; let empty = Query::new(";"); server - .send(vec![ProtocolMessage::from(empty)]) + .send(&vec![ProtocolMessage::from(empty)].into()) .await .unwrap(); @@ -739,9 +856,12 @@ pub mod test { async fn test_set() { let mut server = test_server().await; server - .send(vec![ProtocolMessage::from(Query::new( - "SET application_name TO 'test'", - ))]) + .send( + &vec![ProtocolMessage::from(Query::new( + "SET application_name TO 'test'", + ))] + .into(), + ) .await .unwrap(); @@ -758,21 +878,25 @@ pub mod test { let mut server = test_server().await; use crate::net::bind::Parameter; for _ in 0..25 { - let bind = Bind { - params: vec![Parameter { + let bind = Bind::test_params_codes( + "", + &[Parameter { len: 1, data: "1".as_bytes().to_vec(), }], - codes: vec![0], - ..Default::default() - }; + &[Format::Text], + ); + server - .send(vec![ - ProtocolMessage::from(Parse::new_anonymous("SELECT $1")), - ProtocolMessage::from(bind), - ProtocolMessage::from(Execute::new()), - ProtocolMessage::from(Sync::new()), - ]) + .send( + &vec![ + ProtocolMessage::from(Parse::new_anonymous("SELECT $1")), + ProtocolMessage::from(bind), + ProtocolMessage::from(Execute::new()), + ProtocolMessage::from(Sync::new()), + ] + .into(), + ) .await .unwrap(); @@ -799,21 +923,23 @@ pub mod test { assert!(new); let describe = Describe::new_statement(&name); - let bind = Bind { - statement: name.clone(), - params: vec![Parameter { + let bind = Bind::test_params( + &name, + &[Parameter { len: 1, data: "1".as_bytes().to_vec(), }], - ..Default::default() - }; + ); server - .send(vec![ - ProtocolMessage::from(parse.clone()), - ProtocolMessage::from(describe.clone()), - Flush {}.into(), - ]) + .send( + &vec![ + ProtocolMessage::from(parse.clone()), + ProtocolMessage::from(describe.clone()), + Flush {}.into(), + ] + .into(), + ) .await .unwrap(); @@ -830,10 +956,13 @@ pub mod test { .unwrap(); server - .send(vec![ - ProtocolMessage::from(describe.clone()), - ProtocolMessage::from(Flush), - ]) + .send( + &vec![ + ProtocolMessage::from(describe.clone()), + ProtocolMessage::from(Flush), + ] + .into(), + ) .await .unwrap(); for code in ['t', 'T'] { @@ -844,11 +973,14 @@ pub mod test { assert_eq!(server.prepared_statements.state().len(), 0); server - .send(vec![ - ProtocolMessage::from(bind.clone()), - ProtocolMessage::from(Execute::new()), - ProtocolMessage::from(Sync {}), - ]) + .send( + &vec![ + ProtocolMessage::from(bind.clone()), + ProtocolMessage::from(Execute::new()), + ProtocolMessage::from(Sync {}), + ] + .into(), + ) .await .unwrap(); @@ -875,18 +1007,20 @@ pub mod test { for _ in 0..25 { server - .send(vec![ - ProtocolMessage::from(Bind { - statement: "__pgdog_1".into(), - params: vec![Parameter { - len: 1, - data: "1".as_bytes().to_vec(), - }], - ..Default::default() - }), - Execute::new().into(), - Sync {}.into(), - ]) + .send( + &vec![ + ProtocolMessage::from(Bind::test_params( + "__pgdog_1", + &[Parameter { + len: 1, + data: "1".as_bytes().to_vec(), + }], + )), + Execute::new().into(), + Sync {}.into(), + ] + .into(), + ) .await .unwrap(); @@ -905,11 +1039,14 @@ pub mod test { for _ in 0..25 { let parse = Parse::named("test", "SELECT bad syntax;"); server - .send(vec![ - ProtocolMessage::from(parse), - Describe::new_statement("test").into(), - Sync {}.into(), - ]) + .send( + &vec![ + ProtocolMessage::from(parse), + Describe::new_statement("test").into(), + Sync {}.into(), + ] + .into(), + ) .await .unwrap(); for c in ['E', 'Z'] { @@ -928,17 +1065,17 @@ pub mod test { let name = format!("test_{}", i); let parse = Parse::named(&name, "SELECT $1"); let describe = Describe::new_statement(&name); - let bind = Bind { - statement: name.clone(), - ..Default::default() // Missing params. - }; + let bind = Bind::test_statement(&name); server - .send(vec![ - ProtocolMessage::from(parse), - describe.into(), - bind.into(), - Sync.into(), - ]) + .send( + &vec![ + ProtocolMessage::from(parse), + describe.into(), + bind.into(), + Sync.into(), + ] + .into(), + ) .await .unwrap(); @@ -960,11 +1097,14 @@ pub mod test { for _ in 0..25 { server - .send(vec![ - ProtocolMessage::from(parse.clone()), - describe.clone().into(), - Flush.into(), - ]) + .send( + &vec![ + ProtocolMessage::from(parse.clone()), + describe.clone().into(), + Flush.into(), + ] + .into(), + ) .await .unwrap(); @@ -982,7 +1122,7 @@ pub mod test { let parse = Parse::named(&name, "SELECT bad syntax"); server - .send(vec![ProtocolMessage::from(parse.clone()), Sync.into()]) + .send(&vec![ProtocolMessage::from(parse.clone()), Sync.into()].into()) .await .unwrap(); for c in ['E', 'Z'] { @@ -992,10 +1132,13 @@ pub mod test { assert!(server.prepared_statements.is_empty()); server - .send(vec![ - ProtocolMessage::from(Parse::named("test", "SELECT $1")), - Flush.into(), - ]) + .send( + &vec![ + ProtocolMessage::from(Parse::named("test", "SELECT $1")), + Flush.into(), + ] + .into(), + ) .await .unwrap(); @@ -1030,7 +1173,10 @@ pub mod test { async fn test_multiple_queries() { let mut server = test_server().await; let q = Query::new("SELECT 1; SELECT 2;"); - server.send(vec![ProtocolMessage::from(q)]).await.unwrap(); + server + .send(&vec![ProtocolMessage::from(q)].into()) + .await + .unwrap(); for c in ['T', 'D', 'C', 'T', 'D', 'C', 'Z'] { let msg = server.read().await.unwrap(); assert_eq!(c, msg.code()); @@ -1045,25 +1191,20 @@ pub mod test { Describe::new_statement("test_1").into(), Flush.into(), Query::new("BEGIN").into(), - Bind { - statement: "test_1".into(), - params: vec![crate::net::bind::Parameter { + Bind::test_params( + "test_1", + &[crate::net::bind::Parameter { len: 1, data: "1".as_bytes().to_vec(), }], - ..Default::default() - } - .into(), - Describe { - statement: "".into(), - kind: 'P', - } + ) .into(), + Describe::new_portal("").into(), Execute::new().into(), Sync.into(), Query::new("COMMIT").into(), ]; - server.send(msgs).await.unwrap(); + server.send(&msgs.into()).await.unwrap(); for c in ['1', 't', 'T', 'C', 'Z', '2', 'T', 'D', 'C', 'Z', 'C'] { let msg = server.read().await.unwrap(); @@ -1085,17 +1226,13 @@ pub mod test { Query::new("CREATE TABLE IF NOT EXISTS test_delete (id BIGINT PRIMARY KEY)").into(), ProtocolMessage::from(Parse::named("test", "DELETE FROM test_delete")), Describe::new_statement("test").into(), - Bind { - statement: "test".into(), - ..Default::default() - } - .into(), + Bind::test_statement("test").into(), Execute::new().into(), Sync.into(), Query::new("ROLLBACK").into(), ]; - server.send(msgs).await.unwrap(); + server.send(&msgs.into()).await.unwrap(); for code in ['C', 'Z', 'C', 'Z', '1', 't', 'n', '2', 'C', 'Z', 'C'] { assert!(!server.done()); let msg = server.read().await.unwrap(); @@ -1115,32 +1252,21 @@ pub mod test { Parse::named("test", "SELECT $1").into(), Parse::named("test_2", "SELECT $1, $2, $3").into(), Describe::new_statement("test_2").into(), - Bind { - statement: "test".into(), - params: vec![crate::net::bind::Parameter { + Bind::test_params( + "test", + &[crate::net::bind::Parameter { len: 1, data: "1".as_bytes().to_vec(), }], - ..Default::default() - } - .into(), - Bind { - // Should error out - statement: "test_2".into(), - ..Default::default() - } + ) .into(), + Bind::test_statement("test_2").into(), Execute::new().into(), // Will be ignored - Bind { - // Will be ignored - statement: "test".into(), - ..Default::default() - } - .into(), + Bind::test_statement("test").into(), Flush.into(), ]; - server.send(msgs).await.unwrap(); + server.send(&msgs.into()).await.unwrap(); for c in ['C', 'Z', '1', '1', 't', 'T', '2', 'E'] { let msg = server.read().await.unwrap(); @@ -1153,10 +1279,7 @@ pub mod test { assert!(!server.prepared_statements.state().in_sync()); server - .send(vec![ - ProtocolMessage::from(Sync), - Query::new("SELECT 1").into(), - ]) + .send(&vec![ProtocolMessage::from(Sync), Query::new("SELECT 1").into()].into()) .await .unwrap(); @@ -1174,10 +1297,13 @@ pub mod test { for _ in 0..5 { server - .send(vec![ - ProtocolMessage::from(Parse::named("test", "SELECT $1")), - Sync.into(), - ]) + .send( + &vec![ + ProtocolMessage::from(Parse::named("test", "SELECT $1")), + Sync.into(), + ] + .into(), + ) .await .unwrap(); @@ -1189,21 +1315,23 @@ pub mod test { assert!(server.done()); server - .send(vec![ - Bind { - statement: "test".into(), - params: vec![crate::net::bind::Parameter { - len: 1, - data: "1".as_bytes().to_vec(), - }], - ..Default::default() - } + .send( + &vec![ + Bind::test_params( + "test", + &[crate::net::bind::Parameter { + len: 1, + data: "1".as_bytes().to_vec(), + }], + ) + .into(), + Execute::new().into(), + Close::named("test_sdf").into(), + ProtocolMessage::from(Parse::named("test", "SELECT $1")), + Sync.into(), + ] .into(), - Execute::new().into(), - Close::named("test_sdf").into(), - ProtocolMessage::from(Parse::named("test", "SELECT $1")), - Sync.into(), - ]) + ) .await .unwrap(); assert!(!server.done()); @@ -1222,7 +1350,7 @@ pub mod test { async fn test_just_sync() { let mut server = test_server().await; server - .send(vec![ProtocolMessage::from(Sync)]) + .send(&vec![ProtocolMessage::from(Sync)].into()) .await .unwrap(); assert!(!server.done()); @@ -1235,18 +1363,16 @@ pub mod test { async fn test_portal() { let mut server = test_server().await; server - .send(vec![ - ProtocolMessage::from(Parse::named("test", "SELECT 1")), - Bind { - statement: "test".into(), - portal: "test1".into(), - ..Default::default() - } + .send( + &vec![ + ProtocolMessage::from(Parse::named("test", "SELECT 1")), + Bind::test_name_portal("test", "test1").into(), + Execute::new_portal("test1").into(), + Close::portal("test1").into(), + Sync.into(), + ] .into(), - Execute::new_portal("test1").into(), - Close::portal("test1").into(), - Sync.into(), - ]) + ) .await .unwrap(); @@ -1271,11 +1397,14 @@ pub mod test { assert_eq!(parse.name(), "__pgdog_1"); server - .send(vec![ProtocolMessage::from(Query::new(format!( - "PREPARE {} AS {}", - parse.name(), - parse.query() - )))]) + .send( + &vec![ProtocolMessage::from(Query::new(format!( + "PREPARE {} AS {}", + parse.name(), + parse.query() + )))] + .into(), + ) .await .unwrap(); for c in ['C', 'Z'] { @@ -1287,18 +1416,18 @@ pub mod test { assert!(server.prepared_statements.contains("__pgdog_1")); let describe = Describe::new_statement("__pgdog_1"); - let bind = Bind { - statement: "__pgdog_1".into(), - ..Default::default() - }; + let bind = Bind::test_statement("__pgdog_1"); let execute = Execute::new(); server - .send(vec![ - describe.clone().into(), - bind.into(), - execute.into(), - ProtocolMessage::from(Sync), - ]) + .send( + &vec![ + describe.clone().into(), + bind.into(), + execute.into(), + ProtocolMessage::from(Sync), + ] + .into(), + ) .await .unwrap(); @@ -1311,11 +1440,7 @@ pub mod test { let describe = describe.clone(); server - .send(vec![ - parse.into(), - describe.into(), - ProtocolMessage::from(Flush), - ]) + .send(&vec![parse.into(), describe.into(), ProtocolMessage::from(Flush)].into()) .await .unwrap(); @@ -1325,7 +1450,7 @@ pub mod test { } server - .send(vec![ProtocolMessage::from(Query::new("EXECUTE __pgdog_1"))]) + .send(&vec![ProtocolMessage::from(Query::new("EXECUTE __pgdog_1"))].into()) .await .unwrap(); for c in ['T', 'D', 'C', 'Z'] { @@ -1345,7 +1470,8 @@ pub mod test { let mut server = test_server().await; let mut params = Parameters::default(); params.insert("application_name", "test_sync_params"); - let changed = server.link_client(¶ms, true).await.unwrap(); + println!("server state: {}", server.stats().state); + let changed = server.link_client(¶ms).await.unwrap(); assert_eq!(changed, 1); let app_name = server @@ -1354,7 +1480,110 @@ pub mod test { .unwrap(); assert_eq!(app_name[0], "test_sync_params"); - let changed = server.link_client(¶ms, true).await.unwrap(); + let changed = server.link_client(¶ms).await.unwrap(); + assert_eq!(changed, 0); + } + + #[tokio::test] + async fn test_rollback() { + let mut server = test_server().await; + server + .send(&vec![Query::new("COMMIT").into()].into()) + .await + .unwrap(); + loop { + let msg = server.read().await.unwrap(); + if msg.code() == 'Z' { + break; + } + println!("{:?}", msg); + } + } + + #[tokio::test] + async fn test_partial_state() -> Result<(), Box> { + crate::logger(); + let mut server = test_server().await; + + server + .send( + &vec![ + Parse::named("test", "SELECT $1").into(), + Describe::new_statement("test").into(), + Flush.into(), + ] + .into(), + ) + .await?; + + for c in ['1', 't', 'T'] { + let msg = server.read().await?; + assert_eq!(msg.code(), c); + if c == 'T' { + assert!(server.done()); + } else { + assert!(!server.done()); + } + } + + assert!(server.needs_drain()); + assert!(!server.has_more_messages()); + assert!(server.done()); + server.drain().await; + assert!(server.in_sync()); + assert!(server.done()); + assert!(!server.needs_drain()); + + server + .send( + &vec![ + Query::new("BEGIN").into(), + Query::new("syntax error").into(), + ] + .into(), + ) + .await?; + + for c in ['C', 'Z', 'E'] { + let msg = server.read().await?; + assert_eq!(msg.code(), c); + } + + assert!(!server.needs_drain()); + assert!(server.in_transaction()); + server.drain().await; // Nothing will be done. + assert!(server.in_transaction()); + server.rollback().await; + assert!(server.in_sync()); + assert!(!server.in_transaction()); + + Ok(()) + } + + #[tokio::test] + async fn test_params_sync() -> Result<(), Box> { + let mut params = Parameters::default(); + params.insert("application_name", "test"); + + let mut server = test_server().await; + + let changed = server.link_client(¶ms).await?; + assert_eq!(changed, 1); + + let changed = server.link_client(¶ms).await?; assert_eq!(changed, 0); + + for i in 0..25 { + let value = format!("apples_{}", i); + params.insert("application_name", value); + + let changed = server.link_client(¶ms).await?; + assert_eq!(changed, 2); // RESET, SET. + + let changed = server.link_client(¶ms).await?; + assert_eq!(changed, 0); + } + + Ok(()) } } diff --git a/pgdog/src/backend/server_options.rs b/pgdog/src/backend/server_options.rs index 3ea81f59..b067d275 100644 --- a/pgdog/src/backend/server_options.rs +++ b/pgdog/src/backend/server_options.rs @@ -1,12 +1,6 @@ use crate::net::Parameter; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct ServerOptions { pub params: Vec, } - -impl Default for ServerOptions { - fn default() -> Self { - Self { params: vec![] } - } -} diff --git a/pgdog/src/backend/stats.rs b/pgdog/src/backend/stats.rs index da776488..e385beb1 100644 --- a/pgdog/src/backend/stats.rs +++ b/pgdog/src/backend/stats.rs @@ -2,14 +2,18 @@ use std::{ ops::Add, - time::{Duration, Instant, SystemTime}, + time::{Duration, SystemTime}, }; use fnv::FnvHashMap as HashMap; use once_cell::sync::Lazy; use parking_lot::Mutex; +use tokio::time::Instant; -use crate::{net::messages::BackendKeyData, state::State}; +use crate::{ + net::{messages::BackendKeyData, Parameters}, + state::State, +}; use super::pool::Address; @@ -39,6 +43,7 @@ fn disconnect(id: &BackendKeyData) { pub struct ConnectedServer { pub stats: Stats, pub addr: Address, + pub application_name: String, } /// Server connection stats. @@ -98,7 +103,7 @@ pub struct Stats { impl Stats { /// Register new server with statistics. - pub fn connect(id: BackendKeyData, addr: &Address) -> Self { + pub fn connect(id: BackendKeyData, addr: &Address, params: &Parameters) -> Self { let now = Instant::now(); let stats = Stats { id, @@ -119,6 +124,7 @@ impl Stats { ConnectedServer { stats, addr: addr.clone(), + application_name: params.get_default("application_name", "PgDog").to_owned(), }, ); @@ -138,11 +144,25 @@ impl Stats { self.update(); } + pub fn link_client(&mut self, client: &str, server: &str) { + if client != server { + let mut guard = STATS.lock(); + if let Some(entry) = guard.get_mut(&self.id) { + entry.application_name.clear(); + entry.application_name.push_str(client); + } + } + } + pub fn parse_complete(&mut self) { self.total.parse += 1; self.last_checkout.parse += 1; } + pub fn copy_mode(&mut self) { + self.state(State::CopyMode); + } + pub fn bind_complete(&mut self) { self.total.bind += 1; self.last_checkout.bind += 1; @@ -175,24 +195,33 @@ impl Stats { } } + pub(crate) fn set_timers(&mut self, now: Instant) { + self.transaction_timer = Some(now); + self.query_timer = Some(now); + } + /// Manual state change. pub fn state(&mut self, state: State) { let update = self.state != state; self.state = state; if update { - if state == State::Active { - let now = Instant::now(); - if self.transaction_timer.is_none() { - self.transaction_timer = Some(now); - } - if self.query_timer.is_none() { - self.query_timer = Some(now); - } - } + self.activate(); self.update(); } } + fn activate(&mut self) { + if self.state == State::Active { + let now = Instant::now(); + if self.transaction_timer.is_none() { + self.transaction_timer = Some(now); + } + if self.query_timer.is_none() { + self.query_timer = Some(now); + } + } + } + /// Send bytes to server. pub fn send(&mut self, bytes: usize) { self.total.bytes_sent += bytes; diff --git a/pgdog/src/config/convert.rs b/pgdog/src/config/convert.rs index b9b85180..969c4909 100644 --- a/pgdog/src/config/convert.rs +++ b/pgdog/src/config/convert.rs @@ -5,7 +5,11 @@ use super::User; impl User { pub(crate) fn from_params(params: &Parameters, password: &Password) -> Result { - let user = params.get("user").ok_or(Error::IncompleteStartup)?; + let user = params + .get("user") + .ok_or(Error::IncompleteStartup)? + .as_str() + .ok_or(Error::IncompleteStartup)?; let database = params.get_default("database", user); let password = password.password().ok_or(Error::IncompleteStartup)?; diff --git a/pgdog/src/config/mod.rs b/pgdog/src/config/mod.rs index fb38aa34..ec6d23e9 100644 --- a/pgdog/src/config/mod.rs +++ b/pgdog/src/config/mod.rs @@ -13,7 +13,6 @@ use std::fs::read_to_string; use std::net::Ipv4Addr; use std::sync::Arc; use std::time::Duration; -use std::u64; use std::{collections::HashMap, path::PathBuf}; use arc_swap::ArcSwap; @@ -37,7 +36,11 @@ pub fn config() -> Arc { /// Load the configuration file from disk. pub fn load(config: &PathBuf, users: &PathBuf) -> Result { - let mut config = ConfigAndUsers::load(config, users)?; + let config = ConfigAndUsers::load(config, users)?; + set(config) +} + +pub fn set(mut config: ConfigAndUsers) -> Result { config.config.check(); for table in config.config.sharded_tables.iter_mut() { table.load_centroids()?; @@ -115,6 +118,10 @@ impl ConfigAndUsers { warn!("admin password has been randomly generated"); } + if config.multi_tenant.is_some() { + info!("multi-tenant protection enabled"); + } + let users: Users = if let Ok(users) = read_to_string(users_path) { let mut users: Users = toml::from_str(&users)?; users.check(&config); @@ -154,6 +161,8 @@ pub struct Config { /// TCP settings #[serde(default)] pub tcp: Tcp, + /// Multi-tenant + pub multi_tenant: Option, /// Servers. #[serde(default)] pub databases: Vec, @@ -247,6 +256,11 @@ impl Config { } } } + + /// Multi-tenanncy is enabled. + pub fn multi_tenant(&self) -> &Option { + &self.multi_tenant + } } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -288,6 +302,8 @@ pub struct General { /// Load balancing strategy. #[serde(default = "General::load_balancing_strategy")] pub load_balancing_strategy: LoadBalancingStrategy, + #[serde(default)] + pub read_write_strategy: ReadWriteStrategy, /// TLS certificate. pub tls_certificate: Option, /// TLS private key. @@ -325,6 +341,11 @@ pub struct General { /// Idle timeout. #[serde(default = "General::idle_timeout")] pub idle_timeout: u64, + /// Mirror queue size. + #[serde(default = "General::mirror_queue")] + pub mirror_queue: usize, + #[serde(default)] + pub auth_type: AuthType, } #[derive(Serialize, Deserialize, Debug, Clone, Default)] @@ -355,6 +376,37 @@ pub enum PassthoughAuth { EnabledPlain, } +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum AuthType { + Md5, + #[default] + Scram, + Trust, +} + +impl AuthType { + pub fn md5(&self) -> bool { + matches!(self, Self::Md5) + } + + pub fn scram(&self) -> bool { + matches!(self, Self::Scram) + } + + pub fn trust(&self) -> bool { + matches!(self, Self::Trust) + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Copy)] +#[serde(rename_all = "snake_case")] +pub enum ReadWriteStrategy { + #[default] + Conservative, + Aggressive, +} + impl Default for General { fn default() -> Self { Self { @@ -370,6 +422,7 @@ impl Default for General { ban_timeout: Self::ban_timeout(), rollback_timeout: Self::rollback_timeout(), load_balancing_strategy: Self::load_balancing_strategy(), + read_write_strategy: ReadWriteStrategy::default(), tls_certificate: None, tls_private_key: None, shutdown_timeout: Self::default_shutdown_timeout(), @@ -384,6 +437,8 @@ impl Default for General { checkout_timeout: Self::checkout_timeout(), dry_run: bool::default(), idle_timeout: Self::idle_timeout(), + mirror_queue: Self::mirror_queue(), + auth_type: AuthType::default(), } } } @@ -398,7 +453,7 @@ impl General { } fn workers() -> usize { - 0 + 2 } fn default_pool_size() -> usize { @@ -461,6 +516,10 @@ impl General { Duration::from_secs(5).as_millis() as u64 } + fn mirror_queue() -> usize { + 128 + } + /// Get shutdown timeout as a duration. pub fn shutdown_timeout(&self) -> Duration { Duration::from_millis(self.shutdown_timeout) @@ -548,6 +607,10 @@ pub struct Database { pub statement_timeout: Option, /// Idle timeout. pub idle_timeout: Option, + /// Mirror of another database. + pub mirror_of: Option, + /// Read-only mode. + pub read_only: Option, } impl Database { @@ -659,6 +722,8 @@ pub struct User { pub replication_sharding: Option, /// Idle timeout. pub idle_timeout: Option, + /// Read-only mode. + pub read_only: Option, } impl User { @@ -868,6 +933,12 @@ impl Tcp { } } +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] +#[serde(rename_all = "snake_case")] +pub struct MultiTenant { + pub column: String, +} + #[cfg(test)] mod test { use super::*; @@ -897,6 +968,9 @@ retries = 5 [[plugins]] name = "pgdog_routing" + +[multi_tenant] +column = "tenant_id" "#; let config: Config = toml::from_str(source).unwrap(); @@ -910,5 +984,6 @@ name = "pgdog_routing" ); assert_eq!(config.tcp.time().unwrap(), Duration::from_millis(1000)); assert_eq!(config.tcp.retries().unwrap(), 5); + assert_eq!(config.multi_tenant.unwrap().column, "tenant_id"); } } diff --git a/pgdog/src/frontend/buffer.rs b/pgdog/src/frontend/buffer.rs index 20190b06..be163ae3 100644 --- a/pgdog/src/frontend/buffer.rs +++ b/pgdog/src/frontend/buffer.rs @@ -27,7 +27,9 @@ impl Default for Buffer { impl Buffer { /// Create new buffer. pub fn new() -> Self { - Self { buffer: vec![] } + Self { + buffer: Vec::with_capacity(5), + } } /// Client likely wants to communicate asynchronously. @@ -83,7 +85,7 @@ impl Buffer { if !bind.anonymous() { return Ok(PreparedStatements::global() .lock() - .parse(&bind.statement) + .parse(bind.statement()) .map(BufferedQuery::Prepared)); } } @@ -91,7 +93,7 @@ impl Buffer { if !describe.anonymous() { return Ok(PreparedStatements::global() .lock() - .parse(&describe.statement) + .parse(describe.statement()) .map(BufferedQuery::Prepared)); } } @@ -147,7 +149,7 @@ impl Buffer { /// The client is setting state on the connection /// which we can no longer ignore. - pub fn executable(&self) -> bool { + pub(crate) fn executable(&self) -> bool { self.buffer .iter() .any(|m| ['E', 'Q', 'B'].contains(&m.code())) @@ -208,6 +210,14 @@ impl BufferedQuery { Self::Prepared(parse) => parse.query(), } } + + pub fn extended(&self) -> bool { + matches!(self, Self::Prepared(_)) + } + + pub fn simple(&self) -> bool { + matches!(self, Self::Query(_)) + } } impl Deref for BufferedQuery { diff --git a/pgdog/src/frontend/client/inner.rs b/pgdog/src/frontend/client/inner.rs index 3dceb5eb..96594a68 100644 --- a/pgdog/src/frontend/client/inner.rs +++ b/pgdog/src/frontend/client/inner.rs @@ -7,8 +7,9 @@ use crate::{ }, frontend::{ buffer::BufferedQuery, router::Error as RouterError, Buffer, Command, Comms, - PreparedStatements, Router, Stats, + PreparedStatements, Router, RouterContext, Stats, }, + net::Parameters, state::State, }; @@ -73,12 +74,22 @@ impl Inner { &mut self, buffer: &mut Buffer, prepared_statements: &mut PreparedStatements, + params: &Parameters, ) -> Result, RouterError> { let command = self .backend .cluster() .ok() - .map(|cluster| self.router.query(buffer, cluster, prepared_statements)) + .map(|cluster| { + // Build router context. + let context = RouterContext::new( + buffer, // Query and parameters. + cluster, // Cluster configuration. + prepared_statements, // Prepared statements. + params, // Client connection parameters. + )?; + self.router.query(context) + }) .transpose()?; if let Some(Command::Rewrite(query)) = command { @@ -108,6 +119,18 @@ impl Inner { self.backend.disconnect(); } + pub(super) async fn handle_buffer( + &mut self, + buffer: &Buffer, + streaming: bool, + ) -> Result<(), Error> { + self.backend + .handle_buffer(buffer, &mut self.router, streaming) + .await?; + + Ok(()) + } + /// Connect to a backend (or multiple). pub(super) async fn connect(&mut self, request: &Request) -> Result<(), BackendError> { // Use currently determined route. @@ -120,14 +143,13 @@ impl Inner { if result.is_ok() { self.stats.connected(); if let Ok(addr) = self.backend.addr() { - let addrs = addr - .into_iter() - .map(|a| a.to_string()) - .collect::>() - .join(","); debug!( - "client paired with {} [{:.4}ms]", - addrs, + "client paired with [{}] using route [{}] [{:.4}ms]", + addr.into_iter() + .map(|a| a.to_string()) + .collect::>() + .join(","), + route, self.stats.wait_time.as_secs_f64() * 1000.0 ); } diff --git a/pgdog/src/frontend/client/mod.rs b/pgdog/src/frontend/client/mod.rs index 83df9855..c173b424 100644 --- a/pgdog/src/frontend/client/mod.rs +++ b/pgdog/src/frontend/client/mod.rs @@ -3,6 +3,7 @@ use std::net::SocketAddr; use std::time::Instant; +use bytes::BytesMut; use timeouts::Timeouts; use tokio::time::timeout; use tokio::{select, spawn}; @@ -15,7 +16,7 @@ use crate::backend::{ pool::{Connection, Request}, ProtocolMessage, }; -use crate::config; +use crate::config::{self, AuthType}; use crate::frontend::buffer::BufferedQuery; #[cfg(debug_assertions)] use crate::frontend::QueryLogger; @@ -23,6 +24,7 @@ use crate::net::messages::{ Authentication, BackendKeyData, CommandComplete, ErrorResponse, FromBytes, Message, Password, Protocol, ReadyForQuery, ToBytes, }; +use crate::net::NoticeResponse; use crate::net::{parameter::Parameters, Stream}; pub mod counter; @@ -37,6 +39,7 @@ pub struct Client { addr: SocketAddr, stream: Stream, id: BackendKeyData, + connect_params: Parameters, params: Parameters, comms: Comms, admin: bool, @@ -45,6 +48,8 @@ pub struct Client { prepared_statements: PreparedStatements, in_transaction: bool, timeouts: Timeouts, + protocol_buffer: Buffer, + stream_buffer: BytesMut, } impl Client { @@ -61,18 +66,26 @@ impl Client { let admin = database == config.config.admin.name && config.config.admin.user == user; let admin_password = &config.config.admin.password; + let auth_type = &config.config.general.auth_type; let id = BackendKeyData::new(); // Auto database. let exists = databases::databases().exists((user, database)); if !exists && config.config.general.passthrough_auth() { - // Get the password. - stream - .send_flush(&Authentication::ClearTextPassword) - .await?; - let password = stream.read().await?; - let password = Password::from_bytes(password.to_bytes()?)?; + let password = if auth_type.trust() { + // Use empty password. + // TODO: Postgres must be using "trust" auth + // or some other kind of authentication that doesn't require a password. + Password::new_password("") + } else { + // Get the password. + stream + .send_flush(&Authentication::ClearTextPassword) + .await?; + let password = stream.read().await?; + Password::from_bytes(password.to_bytes()?)? + }; let user = config::User::from_params(¶ms, &password).ok(); if let Some(user) = user { databases::add(user); @@ -94,21 +107,31 @@ impl Client { conn.cluster()?.password() }; - let auth_ok = if stream.is_tls() { - let md5 = md5::Client::new(user, password); - stream.send_flush(&md5.challenge()).await?; - let password = Password::from_bytes(stream.read().await?.to_bytes()?)?; - if let Password::PasswordMessage { response } = password { - md5.check(&response) - } else { - false + let auth_type = &config.config.general.auth_type; + let auth_ok = match (auth_type, stream.is_tls()) { + // TODO: SCRAM doesn't work with TLS currently because of + // lack of support for channel binding in our scram library. + // Defaulting to MD5. + (AuthType::Scram, true) | (AuthType::Md5, _) => { + let md5 = md5::Client::new(user, password); + stream.send_flush(&md5.challenge()).await?; + let password = Password::from_bytes(stream.read().await?.to_bytes()?)?; + if let Password::PasswordMessage { response } = password { + md5.check(&response) + } else { + false + } } - } else { - stream.send_flush(&Authentication::scram()).await?; - let scram = Server::new(password); - let res = scram.handle(&mut stream).await; - matches!(res, Ok(true)) + (AuthType::Scram, false) => { + stream.send_flush(&Authentication::scram()).await?; + + let scram = Server::new(password); + let res = scram.handle(&mut stream).await; + matches!(res, Ok(true)) + } + + (AuthType::Trust, _) => true, }; if !auth_ok { @@ -167,12 +190,17 @@ impl Client { admin, streaming: false, shard, - params, + params: params.clone(), + connect_params: params, prepared_statements: PreparedStatements::new(), in_transaction: false, timeouts: Timeouts::from_config(&config.config.general), + protocol_buffer: Buffer::new(), + stream_buffer: BytesMut::new(), }; + drop(conn); + if client.admin { // Admin clients are not waited on during shutdown. spawn(async move { @@ -225,12 +253,12 @@ impl Client { } buffer = self.buffer() => { - let buffer = buffer?; - if buffer.is_empty() { + buffer?; + if self.protocol_buffer.is_empty() { break; } - let disconnect = self.client_messages(inner.get(), buffer).await?; + let disconnect = self.client_messages(inner.get()).await?; if disconnect { break; } @@ -248,27 +276,28 @@ impl Client { } /// Handle client messages. - async fn client_messages( - &mut self, - mut inner: InnerBorrow<'_>, - mut buffer: Buffer, - ) -> Result { - inner.is_async = buffer.is_async(); - inner.stats.received(buffer.len()); + async fn client_messages(&mut self, mut inner: InnerBorrow<'_>) -> Result { + inner.is_async = self.protocol_buffer.is_async(); + inner.stats.received(self.protocol_buffer.len()); #[cfg(debug_assertions)] - if let Some(query) = buffer.query()? { + if let Some(query) = self.protocol_buffer.query()? { debug!( "{} [{}] (in transaction: {})", query.query(), self.addr, self.in_transaction ); - QueryLogger::new(&buffer).log().await?; + QueryLogger::new(&self.protocol_buffer).log().await?; } let connected = inner.connected(); - let command = match inner.command(&mut buffer, &mut self.prepared_statements) { + + let command = match inner.command( + &mut self.protocol_buffer, + &mut self.prepared_statements, + &self.params, + ) { Ok(command) => command, Err(err) => { self.stream @@ -295,6 +324,7 @@ impl Client { if let BufferedQuery::Query(_) = query { self.start_transaction().await?; inner.start_transaction = Some(query.clone()); + self.in_transaction = true; inner.done(true); return Ok(false); } @@ -302,30 +332,24 @@ impl Client { Some(Command::RollbackTransaction) => { inner.start_transaction = None; self.end_transaction(true).await?; + self.in_transaction = false; inner.done(false); return Ok(false); } Some(Command::CommitTransaction) => { inner.start_transaction = None; self.end_transaction(false).await?; + self.in_transaction = false; inner.done(false); return Ok(false); } // TODO: Handling session variables requires a lot more work, // e.g. we need to track RESET as well. - // Some(Command::Set { name, value }) => { - // self.params.insert(name, value); - // self.stream.send(&CommandComplete::new("SET")).await?; - // self.stream - // .send_flush(&ReadyForQuery::in_transaction(self.in_transaction)) - // .await?; - // let state = inner.stats.state; - // if state == State::Active { - // inner.stats.state = State::Idle; - // } - - // return Ok(false); - // } + Some(Command::Set { name, value }) => { + self.params.insert(name, value.clone()); + self.set(inner).await?; + return Ok(false); + } _ => (), }; @@ -336,13 +360,7 @@ impl Client { let query_timeout = self.timeouts.query_timeout(&inner.stats.state); // We may need to sync params with the server // and that reads from the socket. - timeout( - query_timeout, - inner - .backend - .link_client(&self.params, self.prepared_statements.enabled), - ) - .await??; + timeout(query_timeout, inner.backend.link_client(&self.params)).await??; } Err(err) => { if err.no_server() { @@ -360,34 +378,26 @@ impl Client { // a client is actually executing something. // // This prevents us holding open connections to multiple servers - if buffer.executable() { + if self.protocol_buffer.executable() { if let Some(query) = inner.start_transaction.take() { inner.backend.execute(&query).await?; } } - for msg in buffer.iter() { + for msg in self.protocol_buffer.iter() { if let ProtocolMessage::Bind(bind) = msg { inner.backend.bind(bind)? } } - // Handle COPY subprotocol in a potentially sharded context. - if buffer.copy() && !self.streaming { - let rows = inner.router.copy_data(&buffer)?; - if !rows.is_empty() { - inner.backend.send_copy(rows).await?; - inner - .backend - .send(buffer.without_copy_data().into()) - .await?; - } else { - inner.backend.send(buffer.into()).await?; - } - } else { - // Send query to server. - inner.backend.send(buffer.into()).await?; - } + inner + .handle_buffer(&self.protocol_buffer, self.streaming) + .await?; + + inner.stats.memory_used(self.stream_buffer.capacity()); + + // Send traffic to mirrors, if any. + inner.backend.mirror(&self.protocol_buffer); Ok(false) } @@ -414,19 +424,10 @@ impl Client { inner.stats.idle(self.in_transaction); } - trace!("[{}] <- {:#?}", self.addr, message); - - if flush || async_flush || streaming { - self.stream.send_flush(&message).await?; - if async_flush { - inner.is_async = false; - } - } else { - self.stream.send(&message).await?; - } - inner.stats.sent(len); + // Release the connection back into the pool + // before flushing data to client. if inner.backend.done() { let changed_params = inner.backend.changed_params(); if inner.transaction_mode() { @@ -441,14 +442,26 @@ impl Client { if !changed_params.is_empty() { for (name, value) in changed_params.iter() { - debug!("setting client's \"{}\" to '{}'", name, value); + debug!("setting client's \"{}\" to {}", name, value); self.params.insert(name.clone(), value.clone()); } inner.comms.update_params(&self.params); } - if inner.comms.offline() && !self.admin { - return Ok(true); + } + + trace!("[{}] <- {:#?}", self.addr, message); + + if flush || async_flush || streaming { + self.stream.send_flush(&message).await?; + if async_flush { + inner.is_async = false; } + } else { + self.stream.send(&message).await?; + } + + if inner.backend.done() && inner.comms.offline() && !self.admin { + return Ok(true); } Ok(false) @@ -458,21 +471,22 @@ impl Client { /// /// This ensures we don't check out a connection from the pool until the client /// sent a complete request. - async fn buffer(&mut self) -> Result { - let mut buffer = Buffer::new(); + async fn buffer(&mut self) -> Result<(), Error> { + self.protocol_buffer.clear(); + // Only start timer once we receive the first message. let mut timer = None; // Check config once per request. - let config = config(); + let config = config::config(); self.prepared_statements.enabled = config.prepared_statements(); self.timeouts = Timeouts::from_config(&config.config.general); - while !buffer.full() { - let message = match self.stream.read().await { + while !self.protocol_buffer.full() { + let message = match self.stream.read_buf(&mut self.stream_buffer).await { Ok(message) => message.stream(self.streaming).frontend(), Err(_) => { - return Ok(vec![].into()); + return Ok(()); } }; @@ -482,17 +496,14 @@ impl Client { // Terminate (B & F). if message.code() == 'X' { - return Ok(vec![].into()); + return Ok(()); } else { - if self.prepared_statements.enabled { - let message = ProtocolMessage::from_bytes(message.to_bytes()?)?; - if message.extended() { - buffer.push(self.prepared_statements.maybe_rewrite(message)?); - } else { - buffer.push(message); - } + let message = ProtocolMessage::from_bytes(message.to_bytes()?)?; + if message.extended() && self.prepared_statements.enabled { + self.protocol_buffer + .push(self.prepared_statements.maybe_rewrite(message)?); } else { - buffer.push(message.into()) + self.protocol_buffer.push(message); } } } @@ -500,10 +511,10 @@ impl Client { trace!( "request buffered [{:.4}ms]\n{:#?}", timer.unwrap().elapsed().as_secs_f64() * 1000.0, - buffer, + self.protocol_buffer, ); - Ok(buffer) + Ok(()) } /// Tell the client we started a transaction. @@ -528,10 +539,27 @@ impl Client { } else { CommandComplete::new_commit() }; + let mut messages = if !self.in_transaction { + vec![NoticeResponse::from(ErrorResponse::no_transaction()).message()?] + } else { + vec![] + }; + messages.push(cmd.message()?); + messages.push(ReadyForQuery::idle().message()?); + self.stream.send_many(&messages).await?; + debug!("transaction ended"); + Ok(()) + } + + /// Handle SET command. + async fn set(&mut self, mut inner: InnerBorrow<'_>) -> Result<(), Error> { + self.stream.send(&CommandComplete::new("SET")).await?; self.stream - .send_many(&[cmd.message()?, ReadyForQuery::idle().message()?]) + .send_flush(&ReadyForQuery::in_transaction(self.in_transaction)) .await?; - debug!("transaction ended"); + inner.done(self.in_transaction); + inner.comms.update_params(&self.params); + debug!("set"); Ok(()) } } diff --git a/pgdog/src/frontend/error.rs b/pgdog/src/frontend/error.rs index 2aadad68..fbbc4b8e 100644 --- a/pgdog/src/frontend/error.rs +++ b/pgdog/src/frontend/error.rs @@ -1,5 +1,7 @@ //! Frontend errors. +use std::io::ErrorKind; + use thiserror::Error; /// Frontend error. @@ -40,6 +42,9 @@ pub enum Error { #[error("query timeout")] Timeout(#[from] tokio::time::error::Elapsed), + + #[error("join error")] + Join(#[from] tokio::task::JoinError), } impl Error { @@ -53,4 +58,14 @@ impl Error { &Error::Backend(BackendError::Pool(PoolError::CheckoutTimeout)) ) } + + pub(crate) fn disconnect(&self) -> bool { + if let Error::Net(crate::net::Error::Io(err)) = self { + if err.kind() == ErrorKind::UnexpectedEof { + return true; + } + } + + false + } } diff --git a/pgdog/src/frontend/listener.rs b/pgdog/src/frontend/listener.rs index 18e80422..f03b40c7 100644 --- a/pgdog/src/frontend/listener.rs +++ b/pgdog/src/frontend/listener.rs @@ -41,8 +41,8 @@ impl Listener { /// Listen for client connections and handle them. pub async fn listen(&mut self) -> Result<(), Error> { - let listener = TcpListener::bind(&self.addr).await?; info!("🐕 PgDog listening on {}", self.addr); + let listener = TcpListener::bind(&self.addr).await?; let comms = comms(); let shutdown_signal = comms.shutting_down(); let mut sighup = Sighup::new()?; @@ -59,8 +59,10 @@ impl Listener { let future = async move { match Self::handle_client(stream, addr, client_comms).await { Ok(_) => (), - Err(err) => { + Err(err) => if !err.disconnect() { error!("client crashed: {:?}", err); + } else { + info!("client disconnected [{}]", addr); } }; }; @@ -95,17 +97,22 @@ impl Listener { Ok(()) } + /// Shutdown this listener. + pub fn shutdown(&self) { + self.shutdown.notify_one(); + } + fn start_shutdown(&self) { shutdown(); comms().shutdown(); let listener = self.clone(); spawn(async move { - listener.shutdown().await; + listener.execute_shutdown().await; }); } - async fn shutdown(&self) { + async fn execute_shutdown(&self) { let shutdown_timeout = config().config.general.shutdown_timeout(); info!( diff --git a/pgdog/src/frontend/mod.rs b/pgdog/src/frontend/mod.rs index 2e320e2a..e9228e85 100644 --- a/pgdog/src/frontend/mod.rs +++ b/pgdog/src/frontend/mod.rs @@ -21,4 +21,5 @@ pub use prepared_statements::{PreparedStatements, Rewrite}; #[cfg(debug_assertions)] pub use query_logger::QueryLogger; pub use router::{Command, Router}; +pub use router::{RouterContext, SearchPath}; pub use stats::Stats; diff --git a/pgdog/src/frontend/prepared_statements/global_cache.rs b/pgdog/src/frontend/prepared_statements/global_cache.rs index 6efabbd7..0e0f1a22 100644 --- a/pgdog/src/frontend/prepared_statements/global_cache.rs +++ b/pgdog/src/frontend/prepared_statements/global_cache.rs @@ -1,6 +1,7 @@ +use bytes::Bytes; + use crate::net::messages::{Parse, RowDescription}; use std::collections::hash_map::{Entry, HashMap}; -use std::sync::Arc; // Format the globally unique prepared statement // name based on the counter. @@ -29,8 +30,8 @@ impl Statement { /// #[derive(Debug, Clone, PartialEq, Hash, Eq)] struct CacheKey { - query: Arc, - data_types: Arc>, + query: Bytes, + data_types: Bytes, version: usize, } diff --git a/pgdog/src/frontend/prepared_statements/mod.rs b/pgdog/src/frontend/prepared_statements/mod.rs index 24d0974a..d9e7849f 100644 --- a/pgdog/src/frontend/prepared_statements/mod.rs +++ b/pgdog/src/frontend/prepared_statements/mod.rs @@ -97,11 +97,7 @@ mod test { let messages = vec![ Parse::named("__sqlx_1", "SELECT 1").into(), - Bind { - statement: "__sqlx_1".into(), - ..Default::default() - } - .into(), + Bind::test_statement("__sqlx_1").into(), ]; for message in messages { diff --git a/pgdog/src/frontend/prepared_statements/request.rs b/pgdog/src/frontend/prepared_statements/request.rs index 9b7d0c98..f3860abc 100644 --- a/pgdog/src/frontend/prepared_statements/request.rs +++ b/pgdog/src/frontend/prepared_statements/request.rs @@ -34,7 +34,7 @@ impl PreparedRequest { Self::Prepare { name } => name, Self::Describe { name } => name, Self::PrepareNew { name } => name, - Self::Bind { bind } => &bind.statement, + Self::Bind { bind } => bind.statement(), } } diff --git a/pgdog/src/frontend/prepared_statements/rewrite.rs b/pgdog/src/frontend/prepared_statements/rewrite.rs index 7a399ccc..8151e786 100644 --- a/pgdog/src/frontend/prepared_statements/rewrite.rs +++ b/pgdog/src/frontend/prepared_statements/rewrite.rs @@ -43,7 +43,7 @@ impl<'a> Rewrite<'a> { if bind.anonymous() { Ok(bind) } else { - let name = self.statements.name(&bind.statement); + let name = self.statements.name(bind.statement()); if let Some(name) = name { Ok(bind.rename(name)) } else { @@ -57,7 +57,7 @@ impl<'a> Rewrite<'a> { if describe.anonymous() { Ok(describe) } else { - let name = self.statements.name(&describe.statement); + let name = self.statements.name(describe.statement()); if let Some(name) = name { Ok(describe.rename(name)) } else { @@ -86,19 +86,13 @@ mod test { assert_eq!(parse.name(), "__pgdog_1"); assert_eq!(parse.query(), "SELECT * FROM users"); - let bind = Bind { - statement: "__sqlx_1".into(), - ..Default::default() - }; + let bind = Bind::test_statement("__sqlx_1"); let bind = Bind::from_bytes(rewrite.rewrite(bind.into()).unwrap().to_bytes().unwrap()).unwrap(); - assert_eq!(bind.statement, "__pgdog_1"); + assert_eq!(bind.statement(), "__pgdog_1"); - let describe = Describe { - statement: "__sqlx_1".into(), - kind: 'S', - }; + let describe = Describe::new_statement("__sqlx_1"); let describe = Describe::from_bytes( rewrite @@ -108,8 +102,8 @@ mod test { .unwrap(), ) .unwrap(); - assert_eq!(describe.statement, "__pgdog_1"); - assert_eq!(describe.kind, 'S'); + assert_eq!(describe.statement(), "__pgdog_1"); + assert_eq!(describe.kind(), 'S'); assert_eq!(statements.len(), 1); assert_eq!(statements.global.lock().len(), 1); diff --git a/pgdog/src/frontend/router/context.rs b/pgdog/src/frontend/router/context.rs new file mode 100644 index 00000000..926fef96 --- /dev/null +++ b/pgdog/src/frontend/router/context.rs @@ -0,0 +1,40 @@ +use super::Error; +use crate::{ + backend::Cluster, + frontend::{buffer::BufferedQuery, Buffer, PreparedStatements}, + net::{Bind, Parameters}, +}; + +#[derive(Debug)] +pub struct RouterContext<'a> { + /// Prepared statements. + pub prepared_statements: &'a mut PreparedStatements, + /// Bound parameters to the query. + pub bind: Option<&'a Bind>, + /// Query we're looking it. + pub query: Option, + /// Cluster configuration. + pub cluster: &'a Cluster, + /// Client parameters, e.g. search_path. + pub params: &'a Parameters, +} + +impl<'a> RouterContext<'a> { + pub fn new( + buffer: &'a Buffer, + cluster: &'a Cluster, + stmt: &'a mut PreparedStatements, + params: &'a Parameters, + ) -> Result { + let query = buffer.query()?; + let bind = buffer.parameters()?; + + Ok(Self { + query, + bind, + params, + prepared_statements: stmt, + cluster, + }) + } +} diff --git a/pgdog/src/frontend/router/mod.rs b/pgdog/src/frontend/router/mod.rs index 38e34a2d..4be566c2 100644 --- a/pgdog/src/frontend/router/mod.rs +++ b/pgdog/src/frontend/router/mod.rs @@ -1,21 +1,24 @@ //! Query router. -use crate::backend::Cluster; - +pub mod context; pub mod copy; pub mod error; pub mod parser; pub mod request; pub mod round_robin; +pub mod search_path; pub mod sharding; pub use copy::CopyRow; pub use error::Error; pub use parser::{Command, QueryParser, Route}; -use super::{Buffer, PreparedStatements}; +use super::Buffer; +pub use context::RouterContext; +pub use search_path::SearchPath; /// Query router. +#[derive(Debug)] pub struct Router { query_parser: QueryParser, } @@ -45,15 +48,8 @@ impl Router { /// previous route is preserved. This is useful in case the client /// doesn't supply enough information in the buffer, e.g. just issued /// a Describe request to a previously submitted Parse. - pub fn query( - &mut self, - buffer: &Buffer, - cluster: &Cluster, - prepared_statements: &mut PreparedStatements, - ) -> Result<&Command, Error> { - Ok(self - .query_parser - .parse(buffer, cluster, prepared_statements)?) + pub fn query(&mut self, context: RouterContext) -> Result<&Command, Error> { + Ok(self.query_parser.parse(context)?) } /// Parse CopyData messages and shard them. diff --git a/pgdog/src/frontend/router/parser/cache.rs b/pgdog/src/frontend/router/parser/cache.rs index fa42704f..bc816926 100644 --- a/pgdog/src/frontend/router/parser/cache.rs +++ b/pgdog/src/frontend/router/parser/cache.rs @@ -113,11 +113,11 @@ impl Cache { match query { BufferedQuery::Prepared(parse) => self .record_command_for_normalized(parse.query(), route, false) - .map_err(|e| Error::PgQuery(e)), + .map_err(Error::PgQuery), BufferedQuery::Query(query) => { - let query = normalize(query.query()).map_err(|e| Error::PgQuery(e))?; + let query = normalize(query.query()).map_err(Error::PgQuery)?; self.record_command_for_normalized(&query, route, true) - .map_err(|e| Error::PgQuery(e)) + .map_err(Error::PgQuery) } } } diff --git a/pgdog/src/frontend/router/parser/command.rs b/pgdog/src/frontend/router/parser/command.rs index ceff0ee5..a545ed0d 100644 --- a/pgdog/src/frontend/router/parser/command.rs +++ b/pgdog/src/frontend/router/parser/command.rs @@ -1,5 +1,5 @@ use super::*; -use crate::frontend::buffer::BufferedQuery; +use crate::{frontend::buffer::BufferedQuery, net::parameter::ParameterValue}; #[derive(Debug, Clone)] pub enum Command { @@ -10,7 +10,7 @@ pub enum Command { RollbackTransaction, StartReplication, ReplicationMeta, - Set { name: String, value: String }, + Set { name: String, value: ParameterValue }, PreparedStatement(Prepare), Rewrite(String), } diff --git a/pgdog/src/frontend/router/parser/error.rs b/pgdog/src/frontend/router/parser/error.rs index fc74d986..d03d683e 100644 --- a/pgdog/src/frontend/router/parser/error.rs +++ b/pgdog/src/frontend/router/parser/error.rs @@ -42,4 +42,7 @@ pub enum Error { #[error("set shard syntax error")] SetShard, + + #[error("no multi tenant id")] + MultiTenantId, } diff --git a/pgdog/src/frontend/router/parser/insert.rs b/pgdog/src/frontend/router/parser/insert.rs index 835e7094..1f1dab0b 100644 --- a/pgdog/src/frontend/router/parser/insert.rs +++ b/pgdog/src/frontend/router/parser/insert.rs @@ -99,4 +99,25 @@ mod test { _ => panic!("not an insert"), } } + + #[test] + fn test_insert_typecasts() { + let query = + parse("INSERT INTO sharded (id, value) VALUES ($1::INTEGER, $2::VARCHAR)").unwrap(); + let select = query.protobuf.stmts.first().unwrap().stmt.as_ref().unwrap(); + + match &select.node { + Some(NodeEnum::InsertStmt(stmt)) => { + let insert = Insert::new(stmt); + assert_eq!( + insert.tuples(), + vec![Tuple { + values: vec![Value::Placeholder(1), Value::Placeholder(2),] + }] + ) + } + + _ => panic!("not an insert"), + } + } } diff --git a/pgdog/src/frontend/router/parser/key.rs b/pgdog/src/frontend/router/parser/key.rs index 6e1d8b9d..a29e7d19 100644 --- a/pgdog/src/frontend/router/parser/key.rs +++ b/pgdog/src/frontend/router/parser/key.rs @@ -8,4 +8,6 @@ pub enum Key { /// A constant value, e.g. "1", "2", or "'value'" /// which can be parsed from the query text. Constant(String), + /// Null check on a column. + Null, } diff --git a/pgdog/src/frontend/router/parser/mod.rs b/pgdog/src/frontend/router/parser/mod.rs index 328f39eb..b3a42dba 100644 --- a/pgdog/src/frontend/router/parser/mod.rs +++ b/pgdog/src/frontend/router/parser/mod.rs @@ -11,6 +11,7 @@ pub mod csv; pub mod error; pub mod insert; pub mod key; +pub mod multi_tenant; pub mod order_by; pub mod prepare; pub mod query; diff --git a/pgdog/src/frontend/router/parser/multi_tenant.rs b/pgdog/src/frontend/router/parser/multi_tenant.rs new file mode 100644 index 00000000..11fdb9d4 --- /dev/null +++ b/pgdog/src/frontend/router/parser/multi_tenant.rs @@ -0,0 +1,104 @@ +use pg_query::{NodeEnum, ParseResult}; + +use super::Error; +use crate::{ + backend::Schema, + config::MultiTenant, + frontend::{ + router::parser::{Table, WhereClause}, + SearchPath, + }, + net::Parameters, +}; + +pub struct MultiTenantCheck<'a> { + user: &'a str, + config: &'a MultiTenant, + schema: Schema, + ast: &'a ParseResult, + parameters: &'a Parameters, +} + +impl<'a> MultiTenantCheck<'a> { + pub fn new( + user: &'a str, + config: &'a MultiTenant, + schema: Schema, + ast: &'a ParseResult, + parameters: &'a Parameters, + ) -> Self { + Self { + config, + schema, + ast, + parameters, + user, + } + } + + pub fn run(&self) -> Result<(), Error> { + let stmt = self + .ast + .protobuf + .stmts + .first() + .and_then(|s| s.stmt.as_ref()); + + match stmt.and_then(|n| n.node.as_ref()) { + Some(NodeEnum::UpdateStmt(stmt)) => { + let table = stmt.relation.as_ref().map(Table::from); + let where_clause = WhereClause::new(table.map(|t| t.name), &stmt.where_clause); + if let Some(table) = table { + self.check(table, where_clause)?; + } + } + Some(NodeEnum::SelectStmt(stmt)) => { + let table = Table::try_from(&stmt.from_clause).ok(); + let where_clause = WhereClause::new(table.map(|t| t.name), &stmt.where_clause); + + if let Some(table) = table { + self.check(table, where_clause)?; + } + } + Some(NodeEnum::DeleteStmt(stmt)) => { + let table = stmt.relation.as_ref().map(Table::from); + let where_clause = WhereClause::new(table.map(|t| t.name), &stmt.where_clause); + + if let Some(table) = table { + self.check(table, where_clause)?; + } + } + + _ => (), + } + Ok(()) + } + + fn check(&self, table: Table, where_clause: Option) -> Result<(), Error> { + let search_path = SearchPath::new(self.user, self.parameters, &self.schema); + let schemas = search_path.resolve(); + + for schema in schemas { + let schema_table = self + .schema + .get(&(schema.to_owned(), table.name.to_string())); + if let Some(schema_table) = schema_table { + let has_tenant_id = schema_table.columns().contains_key(&self.config.column); + if !has_tenant_id { + continue; + } + + let check = where_clause + .as_ref() + .map(|w| !w.keys(Some(table.name), &self.config.column).is_empty()); + if let Some(true) = check { + return Ok(()); + } else { + return Err(Error::MultiTenantId); + } + } + } + + Ok(()) + } +} diff --git a/pgdog/src/frontend/router/parser/query.rs b/pgdog/src/frontend/router/parser/query.rs index e856b66e..27c92829 100644 --- a/pgdog/src/frontend/router/parser/query.rs +++ b/pgdog/src/frontend/router/parser/query.rs @@ -6,22 +6,28 @@ use std::{ use crate::{ backend::{databases::databases, replication::ShardedColumn, Cluster, ShardingSchema}, - config::config, + config::{config, ReadWriteStrategy}, frontend::{ buffer::BufferedQuery, router::{ + context::RouterContext, parser::{rewrite::Rewrite, OrderBy, Shard}, round_robin, sharding::{shard_param, shard_str, shard_value, Centroids}, CopyRow, }, - Buffer, PreparedStatements, + PreparedStatements, + }, + net::{ + messages::{Bind, CopyData, Vector}, + parameter::ParameterValue, + Parameters, }, - net::messages::{Bind, CopyData, Vector}, }; use super::*; +use multi_tenant::MultiTenantCheck; use once_cell::sync::Lazy; use pg_query::{ fingerprint, parse, @@ -63,16 +69,25 @@ impl QueryParser { self.replication_mode = true; } - pub fn parse( - &mut self, - buffer: &Buffer, - cluster: &Cluster, - prepared_statements: &mut PreparedStatements, - ) -> Result<&Command, Error> { - if let Some(query) = buffer.query()? { - self.command = - self.query(&query, cluster, buffer.parameters()?, prepared_statements)?; + pub fn parse(&mut self, context: RouterContext) -> Result<&Command, Error> { + if let Some(ref query) = context.query { + self.command = self.query( + query, + context.cluster, + context.bind, + context.prepared_statements, + context.params, + )?; + + // If the cluster only has one shard, use direct-to-shard queries. + if let Command::Query(ref mut query) = self.command { + if !matches!(query.shard(), Shard::Direct(_)) && context.cluster.shards().len() == 1 + { + query.set_shard(0); + } + } } + Ok(&self.command) } @@ -103,8 +118,9 @@ impl QueryParser { &mut self, query: &BufferedQuery, cluster: &Cluster, - params: Option<&Bind>, + bind: Option<&Bind>, prepared_statements: &mut PreparedStatements, + params: &Parameters, ) -> Result { // Replication protocol commands // don't have a node in pg_query, @@ -125,8 +141,11 @@ impl QueryParser { let full_prepared_statements = config().config.general.prepared_statements.full(); let sharding_schema = cluster.sharding_schema(); let dry_run = sharding_schema.tables.dry_run(); + let multi_tenant = cluster.multi_tenant(); let router_disabled = shards == 1 && (read_only || write_only); - let parser_disabled = !full_prepared_statements && router_disabled && !dry_run; + let parser_disabled = + !full_prepared_statements && router_disabled && !dry_run && multi_tenant.is_none(); + let rw_strategy = cluster.read_write_strategy(); debug!( "parser is {}", @@ -154,23 +173,29 @@ impl QueryParser { // We already decided where all queries for this // transaction are going to go. - if self.routed { + if self.routed && multi_tenant.is_none() { if dry_run { let cache = Cache::get(); let route = self.route(); cache.record_command(query, &route)?; } - return Ok(self.command.clone()); + if multi_tenant.is_none() { + return Ok(self.command.clone()); + } } + let mut shard = Shard::All; + // Parse hardcoded shard from a query comment. - let shard = super::comment::shard(query, &sharding_schema).map_err(Error::PgQuery)?; + if !router_disabled && !self.routed { + shard = super::comment::shard(query, &sharding_schema).map_err(Error::PgQuery)?; + } // Cluster is read only or write only, traffic split isn't needed, // and prepared statements support is limited to the extended protocol, // don't parse the query further. - if !full_prepared_statements { + if !full_prepared_statements && multi_tenant.is_none() { if let Shard::Direct(_) = shard { if cluster.read_only() { return Ok(Command::Query(Route::read(shard))); @@ -208,6 +233,16 @@ impl QueryParser { return Ok(Command::Rewrite(queries)); } + if let Some(multi_tenant) = multi_tenant { + debug!("running multi-tenant check"); + MultiTenantCheck::new(cluster.user(), multi_tenant, cluster.schema(), &ast, params) + .run()?; + } + + if self.routed { + return Ok(self.command.clone()); + } + // // Get the root AST node. // @@ -235,7 +270,7 @@ impl QueryParser { round_robin::next() % cluster.shards().len(), )))); } else { - let mut command = Self::select(stmt, &sharding_schema, params)?; + let mut command = Self::select(stmt, &sharding_schema, bind)?; let mut omni = false; if let Command::Query(query) = &mut command { // Try to route an all-shard query to one @@ -258,33 +293,51 @@ impl QueryParser { } // SET statements. Some(NodeEnum::VariableSetStmt(ref stmt)) => { - let command = self.set(stmt, &sharding_schema); - - if self.routed { - return command; - } else { - Ok(Command::Query(Route::read(Shard::All))) - } + return self.set(stmt, &sharding_schema, read_only) } // COPY statements. Some(NodeEnum::CopyStmt(ref stmt)) => Self::copy(stmt, cluster), // INSERT statements. - Some(NodeEnum::InsertStmt(ref stmt)) => Self::insert(stmt, &sharding_schema, params), + Some(NodeEnum::InsertStmt(ref stmt)) => Self::insert(stmt, &sharding_schema, bind), // UPDATE statements. Some(NodeEnum::UpdateStmt(ref stmt)) => Self::update(stmt), // DELETE statements. Some(NodeEnum::DeleteStmt(ref stmt)) => Self::delete(stmt), // Transaction control statements, // e.g. BEGIN, COMMIT, etc. - Some(NodeEnum::TransactionStmt(ref stmt)) => match stmt.kind() { - TransactionStmtKind::TransStmtCommit => return Ok(Command::CommitTransaction), - TransactionStmtKind::TransStmtRollback => return Ok(Command::RollbackTransaction), - TransactionStmtKind::TransStmtBegin | TransactionStmtKind::TransStmtStart => { - self.in_transaction = true; - return Ok(Command::StartTransaction(query.clone())); + Some(NodeEnum::TransactionStmt(ref stmt)) => { + // Only allow to intercept transaction statements + // if they are using the simple protocol. + if query.simple() { + // In conservative read write split mode, + // we don't assume anything about transaction contents + // and just send it to the primary. + // + // Only single-statement SELECT queries can be routed + // to a replica. + if *rw_strategy == ReadWriteStrategy::Conservative { + self.routed = true; + return Ok(Command::Query(Route::write(None))); + } + + match stmt.kind() { + TransactionStmtKind::TransStmtCommit => { + return Ok(Command::CommitTransaction) + } + TransactionStmtKind::TransStmtRollback => { + return Ok(Command::RollbackTransaction) + } + TransactionStmtKind::TransStmtBegin + | TransactionStmtKind::TransStmtStart => { + self.in_transaction = true; + return Ok(Command::StartTransaction(query.clone())); + } + _ => Ok(Command::Query(Route::write(None))), + } + } else { + Ok(Command::Query(Route::write(None))) } - _ => Ok(Command::Query(Route::write(None))), - }, + } // All others are not handled. // They are sent to all shards concurrently. _ => Ok(Command::Query(Route::write(None))), @@ -323,6 +376,7 @@ impl QueryParser { // Otherwise, we're wasting time parsing SQL. if !databases.manual_queries().is_empty() { let fingerprint = fingerprint(query).map_err(Error::PgQuery)?; + trace!("fingerprint: {}", fingerprint.hex); let manual_route = databases.manual_query(&fingerprint.hex).cloned(); // TODO: check routing logic required by config. @@ -333,7 +387,7 @@ impl QueryParser { } } - debug!("{:#?}", command); + debug!("query router decision: {:#?}", command); if dry_run { let default_route = Route::write(None); @@ -361,6 +415,7 @@ impl QueryParser { &mut self, stmt: &VariableSetStmt, sharding_schema: &ShardingSchema, + read_only: bool, ) -> Result { match stmt.name.as_str() { "pgdog.shard" => { @@ -377,7 +432,9 @@ impl QueryParser { }) = node { self.routed = true; - return Ok(Command::Query(Route::write(Some(*ival as usize)))); + return Ok(Command::Query( + Route::write(Some(*ival as usize)).set_read(read_only), + )); } } @@ -390,16 +447,14 @@ impl QueryParser { .as_ref() .ok_or(Error::SetShard)?; - if let NodeEnum::AConst(AConst { val: Some(val), .. }) = node { - match val { - Val::Sval(String { sval }) => { - let shard = shard_str(&sval, sharding_schema, &vec![], 0); - self.routed = true; - return Ok(Command::Query(Route::write(shard))); - } - - _ => (), - } + if let NodeEnum::AConst(AConst { + val: Some(Val::Sval(String { sval })), + .. + }) = node + { + let shard = shard_str(sval, sharding_schema, &vec![], 0); + self.routed = true; + return Ok(Command::Query(Route::write(shard).set_read(read_only))); } } @@ -407,52 +462,52 @@ impl QueryParser { // params without touching the server. name => { if !self.in_transaction { - let node = stmt - .args - .first() - .ok_or(Error::SetShard)? - .node - .as_ref() - .ok_or(Error::SetShard)?; - - if let NodeEnum::AConst(AConst { val: Some(val), .. }) = node { - match val { - Val::Sval(String { sval }) => { - return Ok(Command::Set { - name: name.to_string(), - value: sval.to_string(), - }); - } + let mut value = vec![]; - Val::Ival(Integer { ival }) => { - return Ok(Command::Set { - name: name.to_string(), - value: ival.to_string(), - }); - } + for node in &stmt.args { + if let Some(NodeEnum::AConst(AConst { val: Some(val), .. })) = &node.node { + match val { + Val::Sval(String { sval }) => { + value.push(sval.to_string()); + } - Val::Fval(Float { fval }) => { - return Ok(Command::Set { - name: name.to_string(), - value: fval.to_string(), - }); - } + Val::Ival(Integer { ival }) => { + value.push(ival.to_string()); + } + + Val::Fval(Float { fval }) => { + value.push(fval.to_string()); + } + + Val::Boolval(Boolean { boolval }) => { + value.push(boolval.to_string()); + } - Val::Boolval(Boolean { boolval }) => { - return Ok(Command::Set { - name: name.to_string(), - value: boolval.to_string(), - }); + _ => (), } + } + } - _ => (), + match value.len() { + 0 => (), + 1 => { + return Ok(Command::Set { + name: name.to_string(), + value: ParameterValue::String(value.pop().unwrap()), + }) + } + _ => { + return Ok(Command::Set { + name: name.to_string(), + value: ParameterValue::Tuple(value), + }) } } } } } - Ok(Command::Query(Route::read(Shard::All))) + Ok(Command::Query(Route::write(Shard::All).set_read(read_only))) } fn select( @@ -504,6 +559,9 @@ impl QueryParser { } } } + + // Null doesn't help. + Key::Null => (), } } } @@ -708,23 +766,27 @@ impl QueryParser { #[cfg(test)] mod test { - use crate::net::messages::{parse::Parse, Parameter}; + + use crate::net::{ + messages::{parse::Parse, Parameter}, + Format, + }; use super::{super::Shard, *}; + use crate::frontend::{Buffer, RouterContext}; use crate::net::messages::Query; + use crate::net::Parameters; macro_rules! command { ($query:expr) => {{ let query = $query; let mut query_parser = QueryParser::default(); - let command = query_parser - .parse( - &Buffer::from(vec![Query::new(query).into()]), - &Cluster::new_test(), - &mut PreparedStatements::default(), - ) - .unwrap() - .clone(); + let buffer = Buffer::from(vec![Query::new(query).into()]); + let cluster = Cluster::new_test(); + let mut stmt = PreparedStatements::default(); + let params = Parameters::default(); + let context = RouterContext::new(&buffer, &cluster, &mut stmt, ¶ms).unwrap(); + let command = query_parser.parse(context).unwrap().clone(); (command, query_parser) }}; @@ -757,18 +819,16 @@ mod test { data: p.to_vec(), }) .collect::>(); - let bind = Bind { - portal: "".into(), - statement: $name.into(), - codes: $codes.to_vec(), - params, - results: vec![], - }; + let bind = Bind::test_params_codes($name, ¶ms, $codes); let route = QueryParser::default() .parse( - &Buffer::from(vec![parse.into(), bind.into()]), - &Cluster::new_test(), - &mut PreparedStatements::default(), + RouterContext::new( + &Buffer::from(vec![parse.into(), bind.into()]), + &Cluster::new_test(), + &mut PreparedStatements::default(), + &Parameters::default(), + ) + .unwrap(), ) .unwrap() .clone(); @@ -781,7 +841,7 @@ mod test { }}; ($name:expr, $query:expr, $params: expr) => { - parse!($name, $query, $params, []) + parse!($name, $query, $params, &[]) }; } @@ -799,7 +859,15 @@ mod test { let cluster = Cluster::default(); let command = query_parser - .parse(&buffer, &cluster, &mut PreparedStatements::default()) + .parse( + RouterContext::new( + &buffer, + &cluster, + &mut PreparedStatements::default(), + &Parameters::default(), + ) + .unwrap(), + ) .unwrap(); assert!(matches!(command, &Command::StartReplication)); } @@ -816,7 +884,15 @@ mod test { let cluster = Cluster::default(); let command = query_parser - .parse(&buffer, &cluster, &mut PreparedStatements::default()) + .parse( + RouterContext::new( + &buffer, + &cluster, + &mut PreparedStatements::default(), + &Parameters::default(), + ) + .unwrap(), + ) .unwrap(); assert!(matches!(command, &Command::ReplicationMeta)); } @@ -866,7 +942,7 @@ mod test { FROM sharded WHERE sharded.id = $1::INTEGER ORDER BY sharded.id"#, [[0, 0, 0, 1]], - [1] + &[Format::Binary] ); assert!(route.is_read()); assert_eq!(route.shard(), &Shard::Direct(0)) @@ -910,55 +986,169 @@ mod test { assert!(qp.routed); assert!(!qp.in_transaction); - for (_, qp) in [ + for (command, qp) in [ command!("SET TimeZone TO 'UTC'"), command!("SET TIME ZONE 'UTC'"), ] { - // match command { - // Command::Set { name, value } => { - // assert_eq!(name, "timezone"); - // assert_eq!(value, "UTC"); - // } - // _ => panic!("not a set"), - // }; - assert!(qp.routed); + match command { + Command::Set { name, value } => { + assert_eq!(name, "timezone"); + assert_eq!(value, ParameterValue::from("UTC")); + } + _ => panic!("not a set"), + }; + assert!(!qp.routed); assert!(!qp.in_transaction); } - let (_, qp) = command!("SET statement_timeout TO 3000"); - // match command { - // Command::Set { name, value } => { - // assert_eq!(name, "statement_timeout"); - // assert_eq!(value, "3000"); - // } - // _ => panic!("not a set"), - // }; - assert!(qp.routed); + let (command, qp) = command!("SET statement_timeout TO 3000"); + match command { + Command::Set { name, value } => { + assert_eq!(name, "statement_timeout"); + assert_eq!(value, ParameterValue::from("3000")); + } + _ => panic!("not a set"), + }; + assert!(!qp.routed); assert!(!qp.in_transaction); // TODO: user shouldn't be able to set these. // The server will report an error on synchronization. - let (_, qp) = command!("SET is_superuser TO true"); - // match command { - // Command::Set { name, value } => { - // assert_eq!(name, "is_superuser"); - // assert_eq!(value, "true"); - // } - // _ => panic!("not a set"), - // }; - assert!(qp.routed); + let (command, qp) = command!("SET is_superuser TO true"); + match command { + Command::Set { name, value } => { + assert_eq!(name, "is_superuser"); + assert_eq!(value, ParameterValue::from("true")); + } + _ => panic!("not a set"), + }; + assert!(!qp.routed); assert!(!qp.in_transaction); + + let (_, mut qp) = command!("BEGIN"); + let command = qp + .parse( + RouterContext::new( + &vec![Query::new(r#"SET statement_timeout TO 3000"#).into()].into(), + &Cluster::new_test(), + &mut PreparedStatements::default(), + &Parameters::default(), + ) + .unwrap(), + ) + .unwrap(); + match command { + Command::Query(q) => assert!(q.is_write()), + _ => panic!("set should trigger binding"), + } + + let (command, _) = command!("SET search_path TO \"$user\", public, \"APPLES\""); + match command { + Command::Set { name, value } => { + assert_eq!(name, "search_path"); + assert_eq!( + value, + ParameterValue::Tuple(vec!["$user".into(), "public".into(), "APPLES".into()]) + ) + } + _ => panic!("search path"), + } + + let ast = parse("SET statement_timeout TO 1").unwrap(); + let mut qp = QueryParser { + in_transaction: true, + ..Default::default() + }; + + let root = ast.protobuf.stmts.first().unwrap().stmt.as_ref().unwrap(); + match root.node.as_ref() { + Some(NodeEnum::VariableSetStmt(stmt)) => { + for read_only in [true, false] { + let route = qp.set(stmt, &ShardingSchema::default(), read_only).unwrap(); + match route { + Command::Query(route) => { + assert_eq!(route.is_read(), read_only); + } + _ => panic!("not a query"), + } + } + } + + _ => panic!("not a set"), + } } #[test] fn test_transaction() { let (command, qp) = command!("BEGIN"); + match command { + Command::Query(q) => assert!(q.is_write()), + _ => panic!("not a query"), + }; + + assert!(qp.routed); + assert!(!qp.in_transaction); + + let mut cluster = Cluster::new_test(); + cluster.set_read_write_strategy(ReadWriteStrategy::Aggressive); + + let mut qp = QueryParser::default(); + let command = qp + .query( + &BufferedQuery::Query(Query::new("BEGIN")), + &cluster, + None, + &mut PreparedStatements::default(), + &Parameters::default(), + ) + .unwrap(); assert!(matches!( command, Command::StartTransaction(BufferedQuery::Query(_)) )); - assert!(!qp.routed); assert!(qp.in_transaction); + + let route = qp + .query( + &BufferedQuery::Query(Query::new("SET application_name TO 'test'")), + &cluster, + None, + &mut PreparedStatements::default(), + &Parameters::default(), + ) + .unwrap(); + + match route { + Command::Query(q) => { + assert!(q.is_read()); + assert!(cluster.read_only()); + } + + _ => panic!("not a query"), + } + } + + #[test] + fn test_insert_do_update() { + let route = query!("INSERT INTO foo (id) VALUES ($1::UUID) ON CONFLICT (id) DO UPDATE SET id = excluded.id RETURNING id"); + assert!(route.is_write()) + } + + #[test] + fn test_begin_extended() { + let mut qr = QueryParser::default(); + let result = qr + .parse( + RouterContext::new( + &vec![crate::net::Parse::new_anonymous("BEGIN").into()].into(), + &Cluster::new_test(), + &mut PreparedStatements::default(), + &Parameters::default(), + ) + .unwrap(), + ) + .unwrap(); + assert!(matches!(result, Command::Query(_))); } } diff --git a/pgdog/src/frontend/router/parser/route.rs b/pgdog/src/frontend/router/parser/route.rs index c625ffeb..3fd882dd 100644 --- a/pgdog/src/frontend/router/parser/route.rs +++ b/pgdog/src/frontend/router/parser/route.rs @@ -1,3 +1,5 @@ +use std::fmt::Display; + use super::{Aggregate, OrderBy}; #[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)] @@ -7,6 +9,20 @@ pub enum Shard { All, } +impl Display for Shard { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + Self::Direct(shard) => shard.to_string(), + Self::Multi(shards) => format!("{:?}", shards), + Self::All => "all".into(), + } + ) + } +} + impl Shard { pub fn all(&self) -> bool { matches!(self, Shard::All) @@ -44,6 +60,17 @@ pub struct Route { limit: Option, } +impl Display for Route { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "shard={}, role={}", + self.shard, + if self.read { "replica" } else { "primary" } + ) + } +} + impl Default for Route { fn default() -> Self { Self::write(None) @@ -130,4 +157,9 @@ impl Route { self.read = !lock; self } + + pub fn set_read(mut self, read: bool) -> Self { + self.read = read; + self + } } diff --git a/pgdog/src/frontend/router/parser/table.rs b/pgdog/src/frontend/router/parser/table.rs index dc2dbeed..f8d625af 100644 --- a/pgdog/src/frontend/router/parser/table.rs +++ b/pgdog/src/frontend/router/parser/table.rs @@ -21,6 +21,28 @@ impl<'a> TryFrom<&'a Node> for Table<'a> { } } +impl<'a> TryFrom<&'a Vec> for Table<'a> { + type Error = (); + + fn try_from(value: &'a Vec) -> Result { + let name = value + .first() + .and_then(|node| { + node.node.as_ref().map(|node| match node { + NodeEnum::RangeVar(var) => Some(if let Some(ref alias) = var.alias { + alias.aliasname.as_str() + } else { + var.relname.as_str() + }), + _ => None, + }) + }) + .flatten() + .ok_or(())?; + Ok(Self { name, schema: None }) + } +} + impl<'a> From<&'a RangeVar> for Table<'a> { fn from(range_var: &'a RangeVar) -> Self { let name = if let Some(ref alias) = range_var.alias { diff --git a/pgdog/src/frontend/router/parser/value.rs b/pgdog/src/frontend/router/parser/value.rs index 8be08d15..dde0d7fe 100644 --- a/pgdog/src/frontend/router/parser/value.rs +++ b/pgdog/src/frontend/router/parser/value.rs @@ -139,6 +139,13 @@ impl<'a> TryFrom<&'a Option> for Value<'a> { Ok(Value::Null) } } + Some(NodeEnum::TypeCast(cast)) => { + if let Some(ref arg) = cast.arg { + Value::try_from(&arg.node) + } else { + Ok(Value::Null) + } + } _ => Ok(Value::Null), } } diff --git a/pgdog/src/frontend/router/parser/where_clause.rs b/pgdog/src/frontend/router/parser/where_clause.rs index df3a7040..c76f2a72 100644 --- a/pgdog/src/frontend/router/parser/where_clause.rs +++ b/pgdog/src/frontend/router/parser/where_clause.rs @@ -9,33 +9,37 @@ use std::string::String; use super::Key; #[derive(Debug)] -pub struct Column { +pub struct Column<'a> { /// Table name if fully qualified. /// Can be an alias. - pub table: Option, + pub table: Option<&'a str>, /// Column name. - pub name: String, + pub name: &'a str, } #[derive(Debug)] -enum Output { +enum Output<'a> { Parameter(i32), Value(String), Int(i32), - Column(Column), - Filter(Vec, Vec), + Column(Column<'a>), + NullCheck(Column<'a>), + Filter(Vec>, Vec>), } /// Parse `WHERE` clause of a statement looking for sharding keys. #[derive(Debug)] -pub struct WhereClause { - output: Vec, +pub struct WhereClause<'a> { + output: Vec>, } -impl WhereClause { +impl<'a> WhereClause<'a> { /// Parse the `WHERE` clause of a statement and extract /// all possible sharding keys. - pub fn new(table_name: Option<&str>, where_clause: &Option>) -> Option { + pub fn new( + table_name: Option<&'a str>, + where_clause: &'a Option>, + ) -> Option> { let Some(ref where_clause) = where_clause else { return None; }; @@ -55,7 +59,7 @@ impl WhereClause { fn column_match(column: &Column, table: Option<&str>, name: &str) -> bool { if let (Some(table), Some(other_table)) = (table, &column.table) { - if table != other_table { + if &table != other_table { return false; } }; @@ -112,23 +116,43 @@ impl WhereClause { } } + if let Output::NullCheck(c) = output { + if c.name == column_name && c.table == table_name { + keys.push(Key::Null); + } + } + keys } - fn string(node: Option<&Node>) -> Option { + fn string(node: Option<&Node>) -> Option<&str> { if let Some(node) = node { if let Some(NodeEnum::String(ref string)) = node.node { - return Some(string.sval.clone()); + return Some(string.sval.as_str()); } } None } - fn parse(table_name: Option<&str>, node: &Node) -> Vec { + fn parse(table_name: Option<&'a str>, node: &'a Node) -> Vec> { let mut keys = vec![]; match node.node { + Some(NodeEnum::NullTest(ref null_test)) => { + // Only check for IS NULL, IS NOT NULL definitely doesn't help. + if NullTestType::try_from(null_test.nulltesttype) == Ok(NullTestType::IsNull) { + let left = null_test + .arg + .as_ref() + .and_then(|node| Self::parse(table_name, node).pop()); + + if let Some(Output::Column(c)) = left { + keys.push(Output::NullCheck(c)); + } + } + } + Some(NodeEnum::BoolExpr(ref expr)) => { // Only AND expressions can really be asserted. // OR needs both sides to be evaluated and either one @@ -178,7 +202,7 @@ impl WhereClause { let table = if let Some(table) = table { Some(table) } else { - table_name.map(|t| t.to_owned()) + table_name }; if let Some(name) = name { @@ -192,7 +216,7 @@ impl WhereClause { Some(NodeEnum::TypeCast(ref cast)) => { if let Some(ref arg) = cast.arg { - keys.extend(Self::parse(table_name, &arg)); + keys.extend(Self::parse(table_name, arg)); } } @@ -222,4 +246,31 @@ mod test { assert_eq!(keys.pop().unwrap(), Key::Constant("5".into())); } } + + #[test] + fn test_is_null() { + let query = "SELECT * FROM users WHERE tenant_id IS NULL"; + let ast = parse(query).unwrap(); + + let stmt = ast.protobuf.stmts.first().cloned().unwrap().stmt.unwrap(); + + if let Some(NodeEnum::SelectStmt(stmt)) = stmt.node { + let where_ = WhereClause::new(Some("users"), &stmt.where_clause).unwrap(); + assert_eq!( + where_.keys(Some("users"), "tenant_id").pop(), + Some(Key::Null) + ); + } + + // NOT NULL check is basically everyone, so no! + let query = "SELECT * FROM users WHERE tenant_id IS NOT NULL"; + let ast = parse(query).unwrap(); + + let stmt = ast.protobuf.stmts.first().cloned().unwrap().stmt.unwrap(); + + if let Some(NodeEnum::SelectStmt(stmt)) = stmt.node { + let where_ = WhereClause::new(Some("users"), &stmt.where_clause).unwrap(); + assert!(where_.keys(Some("users"), "tenant_id").is_empty()); + } + } } diff --git a/pgdog/src/frontend/router/search_path.rs b/pgdog/src/frontend/router/search_path.rs new file mode 100644 index 00000000..9234d926 --- /dev/null +++ b/pgdog/src/frontend/router/search_path.rs @@ -0,0 +1,53 @@ +use crate::{ + backend::Schema, + net::{parameter::ParameterValue, Parameters}, +}; + +#[derive(Debug)] +pub struct SearchPath<'a> { + search_path: &'a [String], + user: &'a str, +} + +impl<'a> SearchPath<'a> { + /// Return a list of schemas the tables the user can see. + pub(crate) fn resolve(&'a self) -> Vec<&'a str> { + let mut schemas = vec![]; + + for path in self.search_path { + match path.as_str() { + "$user" => schemas.push(self.user), + path => schemas.push(path), + } + } + + schemas + } + + pub(crate) fn new(user: &'a str, params: &'a Parameters, schema: &'a Schema) -> Self { + let default_path = schema.search_path(); + let search_path = match params.get("search_path") { + Some(ParameterValue::Tuple(overriden)) => overriden.as_slice(), + _ => default_path, + }; + Self { search_path, user } + } +} + +#[cfg(test)] +mod test { + + use super::*; + + #[test] + fn test_search_path() { + let param = vec!["$user".into(), "public".into()]; + let user = "pgdog"; + let resolver = SearchPath { + search_path: ¶m, + user, + }; + let res = resolver.resolve(); + assert_eq!(res, vec!["pgdog", "public"]); + } +} diff --git a/pgdog/src/frontend/stats.rs b/pgdog/src/frontend/stats.rs index ecba8166..06e6b581 100644 --- a/pgdog/src/frontend/stats.rs +++ b/pgdog/src/frontend/stats.rs @@ -1,6 +1,7 @@ //! Frontend client statistics. -use std::time::{Duration, Instant, SystemTime}; +use std::time::{Duration, SystemTime}; +use tokio::time::Instant; use crate::state::State; @@ -31,6 +32,7 @@ pub struct Stats { query_timer: Instant, wait_timer: Instant, pub last_request: SystemTime, + pub memory_used: usize, } impl Stats { @@ -51,6 +53,7 @@ impl Stats { query_timer: now, wait_timer: now, last_request: SystemTime::now(), + memory_used: 0, } } @@ -99,6 +102,10 @@ impl Stats { self.bytes_sent += bytes; } + pub(super) fn memory_used(&mut self, memory: usize) { + self.memory_used = memory; + } + pub(super) fn idle(&mut self, in_transaction: bool) { if in_transaction { self.state = State::IdleInTransaction; diff --git a/pgdog/src/lib.rs b/pgdog/src/lib.rs new file mode 100644 index 00000000..ce4fb234 --- /dev/null +++ b/pgdog/src/lib.rs @@ -0,0 +1,41 @@ +pub mod admin; +pub mod auth; +pub mod backend; +pub mod cli; +pub mod config; +pub mod frontend; +pub mod net; +pub mod plugin; +pub mod sighup; +pub mod state; +pub mod stats; +#[cfg(feature = "tui")] +pub mod tui; +pub mod util; + +use tracing::level_filters::LevelFilter; +use tracing_subscriber::{fmt, prelude::*, EnvFilter}; + +use std::io::IsTerminal; + +/// Setup the logger, so `info!`, `debug!` +/// and other macros actually output something. +/// +/// Using try_init and ignoring errors to allow +/// for use in tests (setting up multiple times). +pub fn logger() { + let format = fmt::layer() + .with_ansi(std::io::stderr().is_terminal()) + .with_file(false); + #[cfg(not(debug_assertions))] + let format = format.with_target(false); + + let filter = EnvFilter::builder() + .with_default_directive(LevelFilter::INFO.into()) + .from_env_lossy(); + + let _ = tracing_subscriber::registry() + .with(format) + .with(filter) + .try_init(); +} diff --git a/pgdog/src/main.rs b/pgdog/src/main.rs index 2e44ec0f..a7e7a225 100644 --- a/pgdog/src/main.rs +++ b/pgdog/src/main.rs @@ -1,30 +1,17 @@ //! pgDog, modern PostgreSQL proxy, pooler and query router. -use backend::databases; use clap::Parser; -use cli::Commands; -use config::config; -use frontend::listener::Listener; +use pgdog::backend::databases; +use pgdog::cli::{self, Commands}; +use pgdog::config; +use pgdog::frontend::listener::Listener; +use pgdog::net; +use pgdog::plugin; +use pgdog::stats; use tokio::runtime::Builder; -use tracing::{info, level_filters::LevelFilter}; -use tracing_subscriber::{fmt, prelude::*, EnvFilter}; - -use std::{io::IsTerminal, process::exit}; - -pub mod admin; -pub mod auth; -pub mod backend; -pub mod cli; -pub mod config; -pub mod frontend; -pub mod net; -pub mod plugin; -pub mod sighup; -pub mod state; -pub mod stats; -#[cfg(feature = "tui")] -pub mod tui; -pub mod util; +use tracing::info; + +use std::process::exit; #[cfg(not(target_env = "msvc"))] use tikv_jemallocator::Jemalloc; @@ -33,38 +20,16 @@ use tikv_jemallocator::Jemalloc; #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; -/// Setup the logger, so `info!`, `debug!` -/// and other macros actually output something. -/// -/// Using try_init and ignoring errors to allow -/// for use in tests (setting up multiple times). -fn logger() { - let format = fmt::layer() - .with_ansi(std::io::stderr().is_terminal()) - .with_file(false); - #[cfg(not(debug_assertions))] - let format = format.with_target(false); - - let filter = EnvFilter::builder() - .with_default_directive(LevelFilter::INFO.into()) - .from_env_lossy(); - - let _ = tracing_subscriber::registry() - .with(format) - .with(filter) - .try_init(); -} - fn main() -> Result<(), Box> { let args = cli::Cli::parse(); - logger(); + pgdog::logger(); - let mut overrides = config::Overrides::default(); + let mut overrides = pgdog::config::Overrides::default(); match args.command { Some(Commands::Fingerprint { query, path }) => { - cli::fingerprint(query, path)?; + pgdog::cli::fingerprint(query, path)?; exit(0); } @@ -75,7 +40,7 @@ fn main() -> Result<(), Box> { min_pool_size, session_mode, }) => { - overrides = config::Overrides { + overrides = pgdog::config::Overrides { min_pool_size, session_mode, default_pool_size: pool_size, @@ -125,7 +90,7 @@ async fn pgdog() -> Result<(), Box> { // Load databases and connect if needed. databases::init(); - let general = &config().config.general; + let general = &config::config().config.general; if let Some(broadcast_addr) = general.broadcast_address { net::discovery::Listener::get().run(broadcast_addr, general.broadcast_port); @@ -135,10 +100,17 @@ async fn pgdog() -> Result<(), Box> { tokio::spawn(async move { stats::http_server::server(openmetrics_port).await }); } + let stats_logger = stats::StatsLogger::new(); + + if general.dry_run { + stats_logger.spawn(); + } + let mut listener = Listener::new(format!("{}:{}", general.host, general.port)); listener.listen().await?; info!("🐕 pgDog is shutting down"); + stats_logger.shutdown(); // Any shutdown routines go below. plugin::shutdown(); diff --git a/pgdog/src/net/decoder.rs b/pgdog/src/net/decoder.rs index 8b23a284..72a8bb87 100644 --- a/pgdog/src/net/decoder.rs +++ b/pgdog/src/net/decoder.rs @@ -32,14 +32,16 @@ impl Decoder { /// Infer types from Bind, if any provided. pub fn bind(&mut self, bind: &Bind) { - if !bind.codes.is_empty() { - self.formats = bind.codes(); + // Only override RowDescription formats if + // Bind specifies formats. + if !bind.codes().is_empty() { + self.formats = bind.codes().to_vec(); } if self.rd.is_empty() { if let Some(rd) = PreparedStatements::global() .lock() - .row_description(&bind.statement) + .row_description(bind.statement()) { self.rd = rd; } diff --git a/pgdog/src/net/messages/auth/password.rs b/pgdog/src/net/messages/auth/password.rs index ad38a14c..83bf85ce 100644 --- a/pgdog/src/net/messages/auth/password.rs +++ b/pgdog/src/net/messages/auth/password.rs @@ -11,6 +11,7 @@ pub enum Password { /// SASLInitialResponse (F) SASLInitialResponse { name: String, response: String }, /// PasswordMessage (F) or SASLResponse (F) + /// TODO: This requires a NULL byte at end. Need to rewrite this struct. PasswordMessage { response: String }, } diff --git a/pgdog/src/net/messages/bind.rs b/pgdog/src/net/messages/bind.rs index 86aab59e..b79f7513 100644 --- a/pgdog/src/net/messages/bind.rs +++ b/pgdog/src/net/messages/bind.rs @@ -1,5 +1,5 @@ //! Bind (F) message. -use crate::net::c_string_buf; +use crate::net::c_string_buf_len; use uuid::Uuid; use super::code; @@ -10,8 +10,9 @@ use super::Vector; use std::fmt::Debug; use std::str::from_utf8; +use std::str::from_utf8_unchecked; -#[derive(PartialEq, Debug, Copy, Clone)] +#[derive(PartialEq, Debug, Copy, Clone, PartialOrd, Ord, Eq)] pub enum Format { Text, Binary, @@ -49,7 +50,7 @@ impl Debug for Parameter { } impl Parameter { - pub fn len(&self) -> usize { + pub(crate) fn len(&self) -> usize { 4 + self.data.len() } } @@ -97,26 +98,39 @@ impl ParameterWithFormat<'_> { } /// Bind (F) message. -#[derive(Debug, Clone, Default, PartialEq, PartialOrd, Ord, Eq)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq)] pub struct Bind { /// Portal name. - pub portal: String, + portal: Bytes, /// Prepared statement name. - pub statement: String, + statement: Bytes, /// Format codes. - pub codes: Vec, + codes: Vec, /// Parameters. - pub params: Vec, + params: Vec, /// Results format. - pub results: Vec, + results: Vec, + /// Original payload. + original: Option, +} + +impl Default for Bind { + fn default() -> Self { + Bind { + portal: Bytes::from("\0"), + statement: Bytes::from("\0"), + codes: vec![], + params: vec![], + results: vec![], + original: None, + } + } } impl Bind { pub(crate) fn len(&self) -> usize { self.portal.len() - + 1 // NULL + self.statement.len() - + 1 // NULL + self.codes.len() * std::mem::size_of::() + 2 // num codes + self.params.iter().map(|p| p.len()).sum::() + 2 // num params + self.results.len() * std::mem::size_of::() + 2 // num results @@ -131,18 +145,10 @@ impl Bind { } else if self.codes.len() == 1 { self.codes.first().copied() } else { - Some(0) + Some(Format::Text) }; - if let Some(code) = code { - match code { - 0 => Ok(Format::Text), - 1 => Ok(Format::Binary), - _ => Err(Error::IncorrectParameterFormatCode(code)), - } - } else { - Ok(Format::Text) - } + Ok(code.unwrap_or(Format::Text)) } /// Get parameter at index. @@ -156,38 +162,81 @@ impl Bind { /// Rename this Bind message to a different prepared statement. pub fn rename(mut self, name: impl ToString) -> Self { - self.statement = name.to_string(); + self.statement = Bytes::from(name.to_string() + "\0"); + self.original = None; self } /// Is this Bind message anonymous? pub fn anonymous(&self) -> bool { - self.statement.is_empty() + self.statement.len() == 1 + } + + #[inline] + pub(crate) fn statement(&self) -> &str { + // SAFETY: We check that this is valid UTF-8 in FromBytes::from_bytes below. + unsafe { from_utf8_unchecked(&self.statement[0..self.statement.len() - 1]) } } /// Format codes, if any. - pub fn codes(&self) -> Vec { - self.codes - .iter() - .map(|c| { - if *c == 0 { - Format::Text - } else { - Format::Binary - } - }) - .collect() + pub fn codes(&self) -> &[Format] { + &self.codes + } +} + +#[cfg(test)] +impl Bind { + pub(crate) fn test_statement(name: &str) -> Self { + Self { + statement: Bytes::from(name.to_string() + "\0"), + ..Default::default() + } + } + + pub(crate) fn test_params(name: &str, params: &[Parameter]) -> Self { + Self { + statement: Bytes::from(name.to_string() + "\0"), + params: params.to_vec(), + ..Default::default() + } + } + + pub(crate) fn test_name_portal(name: &str, portal: &str) -> Self { + Self { + statement: Bytes::from(name.to_string() + "\0"), + portal: Bytes::from(portal.to_string() + "\0"), + ..Default::default() + } + } + + pub(crate) fn test_params_codes(name: &str, params: &[Parameter], codes: &[Format]) -> Self { + Self { + statement: Bytes::from(name.to_string() + "\0"), + codes: codes.to_vec(), + params: params.to_vec(), + ..Default::default() + } } } impl FromBytes for Bind { fn from_bytes(mut bytes: Bytes) -> Result { + let original = bytes.clone(); code!(bytes, 'B'); let _len = bytes.get_i32(); - let portal = c_string_buf(&mut bytes); - let statement = c_string_buf(&mut bytes); + + let portal = bytes.split_to(c_string_buf_len(&bytes)); + let statement = bytes.split_to(c_string_buf_len(&bytes)); + from_utf8(&portal[0..portal.len() - 1])?; + from_utf8(&statement[0..statement.len() - 1])?; + let num_codes = bytes.get_i16(); - let codes = (0..num_codes).map(|_| bytes.get_i16()).collect(); + let codes = (0..num_codes) + .map(|_| match bytes.get_i16() { + 0 => Format::Text, + _ => Format::Binary, + }) + .collect(); let num_params = bytes.get_i16(); let params = (0..num_params) .map(|_| { @@ -211,18 +260,29 @@ impl FromBytes for Bind { codes, params, results, + original: Some(original), }) } } impl ToBytes for Bind { fn to_bytes(&self) -> Result { + // Fast path. + if let Some(ref original) = self.original { + return Ok(original.clone()); + } + let mut payload = Payload::named(self.code()); - payload.put_string(&self.portal); - payload.put_string(&self.statement); + payload.reserve(self.len()); + + payload.put(self.portal.clone()); + payload.put(self.statement.clone()); payload.put_i16(self.codes.len() as i16); for code in &self.codes { - payload.put_i16(*code); + payload.put_i16(match code { + Format::Text => 0, + Format::Binary => 1, + }); } payload.put_i16(self.params.len() as i16); for param in &self.params { @@ -260,9 +320,10 @@ mod test { let pool = pool(); let mut conn = pool.get(&Request::default()).await.unwrap(); let bind = Bind { - portal: "".into(), - statement: "__pgdog_1".into(), - codes: vec![1, 0], + original: None, + portal: "\0".into(), + statement: "__pgdog_1\0".into(), + codes: vec![Format::Binary, Format::Text], params: vec![ Parameter { len: 2, @@ -275,9 +336,10 @@ mod test { ], results: vec![0], }; - let bytes = bind.to_bytes().unwrap(); - assert_eq!(Bind::from_bytes(bytes.clone()).unwrap(), bind); + let mut original = Bind::from_bytes(bytes.clone()).unwrap(); + original.original = None; + assert_eq!(original, bind); assert_eq!(bind.len(), bytes.len()); let mut c = bytes.clone(); let _ = c.get_u8(); @@ -285,10 +347,15 @@ mod test { assert_eq!(len as usize + 1, bytes.len()); - conn.send(vec![bind.message().unwrap()]).await.unwrap(); + conn.send(&vec![ProtocolMessage::from(bind)].into()) + .await + .unwrap(); let res = conn.read().await.unwrap(); let err = ErrorResponse::from_bytes(res.to_bytes().unwrap()).unwrap(); assert_eq!(err.code, "26000"); + + let anon = Bind::default(); + assert!(anon.anonymous()); } #[tokio::test] @@ -299,22 +366,25 @@ mod test { let json = r#"[{"name": "force_database_error", "type": "C", "value": "false"}, {"name": "__dbver__", "type": "C", "value": 2}]"#; let jsonb = binary_marker + json; let bind = Bind { - statement: "test".into(), - codes: vec![1], + statement: "test\0".into(), + codes: vec![Format::Binary], params: vec![Parameter { data: jsonb.as_bytes().to_vec(), - len: jsonb.as_bytes().len() as i32, + len: jsonb.len() as i32, }], ..Default::default() }; let execute = Execute::new(); server - .send(vec![ - ProtocolMessage::from(parse), - bind.into(), - execute.into(), - Sync.into(), - ]) + .send( + &vec![ + ProtocolMessage::from(parse), + bind.into(), + execute.into(), + Sync.into(), + ] + .into(), + ) .await .unwrap(); diff --git a/pgdog/src/net/messages/command_complete.rs b/pgdog/src/net/messages/command_complete.rs index 81a269c5..b8a9d01d 100644 --- a/pgdog/src/net/messages/command_complete.rs +++ b/pgdog/src/net/messages/command_complete.rs @@ -1,22 +1,31 @@ //! CommandComplete (B) message. -use crate::net::c_string_buf; +use std::fmt::Debug; +use std::str::from_utf8; +use std::str::from_utf8_unchecked; use super::code; use super::prelude::*; /// CommandComplete (B) message. -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct CommandComplete { - /// Name of the command that was executed. - pub command: String, + payload: Bytes, +} + +impl Debug for CommandComplete { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("CommandComplete") + .field("command", &self.command()) + .finish() + } } impl CommandComplete { /// Number of rows sent/received. pub fn rows(&self) -> Result, Error> { Ok(self - .command + .command() .split(" ") .last() .ok_or(Error::UnexpectedPayload)? @@ -24,63 +33,65 @@ impl CommandComplete { .ok()) } + #[inline] + pub(crate) fn command(&self) -> &str { + unsafe { from_utf8_unchecked(&self.payload[5..self.payload.len() - 1]) } + } + + pub(crate) fn from_str(s: &str) -> Self { + let mut payload = Payload::named('C'); + payload.put_string(s); + + Self { + payload: payload.freeze(), + } + } + /// Rewrite the message with new number of rows. pub fn rewrite(&self, rows: usize) -> Result { - let mut parts = self.command.split(" ").collect::>(); + let mut parts = self.command().split(" ").collect::>(); parts.pop(); let rows = rows.to_string(); parts.push(rows.as_str()); - Ok(Self { - command: parts.join(" "), - }) + Ok(Self::from_str(&parts.join(" "))) } /// Start transaction. pub fn new_begin() -> Self { - Self { - command: "BEGIN".into(), - } + Self::from_str("BEGIN") } /// Rollback transaction. pub fn new_rollback() -> Self { - Self { - command: "ROLLBACK".into(), - } + Self::from_str("ROLLBACK") } /// Commit transaction. pub fn new_commit() -> Self { - Self { - command: "COMMIT".into(), - } + Self::from_str("COMMIT") } pub fn new(command: impl ToString) -> Self { - Self { - command: command.to_string(), - } + Self::from_str(command.to_string().as_str()) } } impl ToBytes for CommandComplete { fn to_bytes(&self) -> Result { - let mut payload = Payload::named(self.code()); - payload.put_string(&self.command); - - Ok(payload.freeze()) + Ok(self.payload.clone()) } } impl FromBytes for CommandComplete { fn from_bytes(mut bytes: Bytes) -> Result { + let original = bytes.clone(); code!(bytes, 'C'); - let _len = bytes.get_i32(); - let command = c_string_buf(&mut bytes); + // Check UTF-8! + from_utf8(&original[5..original.len() - 1])?; - Ok(Self { command }) + Ok(Self { payload: original }) } } diff --git a/pgdog/src/net/messages/describe.rs b/pgdog/src/net/messages/describe.rs index dbed9530..a97e1ece 100644 --- a/pgdog/src/net/messages/describe.rs +++ b/pgdog/src/net/messages/describe.rs @@ -7,23 +7,33 @@ use super::prelude::*; /// Describe (F) message. #[derive(Debug, Clone)] pub struct Describe { - pub kind: char, - pub statement: String, + kind: char, + statement: String, + original: Option, } impl FromBytes for Describe { fn from_bytes(mut bytes: Bytes) -> Result { + let original = bytes.clone(); code!(bytes, 'D'); let _len = bytes.get_i32(); let kind = bytes.get_u8() as char; let statement = c_string_buf(&mut bytes); - Ok(Self { kind, statement }) + Ok(Self { + kind, + statement, + original: Some(original), + }) } } impl ToBytes for Describe { fn to_bytes(&self) -> Result { + if let Some(ref original) = self.original { + return Ok(original.clone()); + } + let mut payload = Payload::named(self.code()); payload.put_u8(self.kind as u8); payload.put_string(&self.statement); @@ -49,6 +59,7 @@ impl Describe { pub fn rename(mut self, name: impl ToString) -> Self { self.statement = name.to_string(); + self.original = None; self } @@ -56,15 +67,38 @@ impl Describe { Describe { kind: 'S', statement: name.to_string(), + original: None, + } + } + + pub fn new_portal(name: &str) -> Describe { + Describe { + kind: 'P', + statement: name.to_string(), + original: None, } } + + #[inline] + pub(crate) fn statement(&self) -> &str { + &self.statement + } + + #[inline] + #[cfg(test)] + pub(crate) fn kind(&self) -> char { + self.kind + } } #[cfg(test)] mod test { use super::*; use crate::{ - backend::pool::{test::pool, Request}, + backend::{ + pool::{test::pool, Request}, + ProtocolMessage, + }, net::messages::ErrorResponse, }; @@ -75,8 +109,11 @@ mod test { let describe = Describe { kind: 'P', statement: "".into(), + original: None, }; - conn.send(vec![describe.message().unwrap()]).await.unwrap(); + conn.send(&vec![ProtocolMessage::from(describe.message().unwrap())].into()) + .await + .unwrap(); let res = conn.read().await.unwrap(); let err = ErrorResponse::from_bytes(res.to_bytes().unwrap()).unwrap(); assert_eq!(err.code, "34000"); diff --git a/pgdog/src/net/messages/error_response.rs b/pgdog/src/net/messages/error_response.rs index 59aa8e2c..85b5dc47 100644 --- a/pgdog/src/net/messages/error_response.rs +++ b/pgdog/src/net/messages/error_response.rs @@ -98,6 +98,17 @@ impl ErrorResponse { routine: None, } } + + pub fn no_transaction() -> Self { + Self { + severity: "WARNING".into(), + code: "25P01".into(), + message: "there is no transaction in progress".into(), + routine: Some("EndTransactionBlock".into()), + file: Some("xact.c".into()), + ..Default::default() + } + } } impl Display for ErrorResponse { @@ -143,6 +154,9 @@ impl ToBytes for ErrorResponse { payload.put_u8(b'S'); payload.put_string(&self.severity); + payload.put_u8(b'V'); + payload.put_string(&self.severity); + payload.put_u8(b'C'); payload.put_string(&self.code); diff --git a/pgdog/src/net/messages/execute.rs b/pgdog/src/net/messages/execute.rs index b8115f0d..038481e4 100644 --- a/pgdog/src/net/messages/execute.rs +++ b/pgdog/src/net/messages/execute.rs @@ -1,3 +1,4 @@ +use std::fmt::Debug; use std::str::from_utf8; use crate::net::c_string_buf_len; @@ -5,7 +6,7 @@ use crate::net::c_string_buf_len; use super::code; use super::prelude::*; -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct Execute { payload: Bytes, portal_len: usize, @@ -17,6 +18,14 @@ impl Default for Execute { } } +impl Debug for Execute { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Execute") + .field("portal", &self.portal()) + .finish() + } +} + impl Execute { pub fn new() -> Self { let mut payload = Payload::named('E'); diff --git a/pgdog/src/net/messages/hello.rs b/pgdog/src/net/messages/hello.rs index 905416ad..4cde0167 100644 --- a/pgdog/src/net/messages/hello.rs +++ b/pgdog/src/net/messages/hello.rs @@ -1,6 +1,10 @@ //! Startup, SSLRequest messages. -use crate::net::{c_string, parameter::Parameters, Error}; +use crate::net::{ + c_string, + parameter::{ParameterValue, Parameters}, + Error, +}; use bytes::{Buf, BufMut, Bytes, BytesMut}; use tokio::io::{AsyncRead, AsyncReadExt}; use tracing::debug; @@ -88,7 +92,7 @@ impl Startup { pub fn parameter(&self, name: &str) -> Option<&str> { match self { Startup::Ssl | Startup::Cancel { .. } => None, - Startup::Startup { params } => params.get(name).map(|s| s.as_str()), + Startup::Startup { params } => params.get(name).and_then(|s| s.as_str()), } } @@ -141,11 +145,13 @@ impl super::ToBytes for Startup { let mut params_buf = BytesMut::new(); for (name, value) in params.deref() { - params_buf.put_slice(name.as_bytes()); - params_buf.put_u8(0); + if let ParameterValue::String(value) = value { + params_buf.put_slice(name.as_bytes()); + params_buf.put_u8(0); - params_buf.put_slice(value.as_bytes()); - params_buf.put_u8(0); + params_buf.put(value.as_bytes()); + params_buf.put_u8(0); + } } let mut payload = Payload::new(); diff --git a/pgdog/src/net/messages/mod.rs b/pgdog/src/net/messages/mod.rs index 8962aecf..f44c9f0a 100644 --- a/pgdog/src/net/messages/mod.rs +++ b/pgdog/src/net/messages/mod.rs @@ -146,7 +146,7 @@ impl std::fmt::Debug for Message { impl ToBytes for Message { fn to_bytes(&self) -> Result { - Ok(self.payload.clone()) + Ok(Bytes::clone(&self.payload)) } } diff --git a/pgdog/src/net/messages/notice_response.rs b/pgdog/src/net/messages/notice_response.rs index 9286e67d..414fd3c7 100644 --- a/pgdog/src/net/messages/notice_response.rs +++ b/pgdog/src/net/messages/notice_response.rs @@ -1,3 +1,5 @@ +use bytes::BytesMut; + use super::{prelude::*, ErrorResponse}; #[derive(Debug)] @@ -12,3 +14,24 @@ impl FromBytes for NoticeResponse { }) } } + +impl ToBytes for NoticeResponse { + fn to_bytes(&self) -> Result { + let mut message = BytesMut::from(self.message.to_bytes()?); + message[0] = self.code() as u8; + + Ok(message.freeze()) + } +} + +impl From for NoticeResponse { + fn from(value: ErrorResponse) -> Self { + Self { message: value } + } +} + +impl Protocol for NoticeResponse { + fn code(&self) -> char { + 'N' + } +} diff --git a/pgdog/src/net/messages/parse.rs b/pgdog/src/net/messages/parse.rs index 12ee5187..a89e456f 100644 --- a/pgdog/src/net/messages/parse.rs +++ b/pgdog/src/net/messages/parse.rs @@ -1,112 +1,169 @@ //! Parse (F) message. -use crate::net::c_string_buf; -use std::sync::Arc; +use crate::net::c_string_buf_len; +use std::fmt::Debug; +use std::io::Cursor; +use std::mem::size_of; +use std::str::from_utf8; +use std::str::from_utf8_unchecked; use super::code; use super::prelude::*; /// Parse (F) message. -#[derive(Debug, Clone, Hash, Eq, PartialEq, Default)] +#[derive(Clone, Hash, Eq, PartialEq, Default)] pub struct Parse { /// Prepared statement name. - name: Arc, + name: Bytes, /// Prepared statement query. - query: Arc, + query: Bytes, /// List of data types if any are declared. - data_types: Arc>, + data_types: Bytes, + /// Original payload. + original: Option, +} + +impl Debug for Parse { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Parse") + .field("name", &self.name()) + .field("query", &self.query()) + .field("modified", &self.original.is_none()) + .finish() + } } impl Parse { pub fn len(&self) -> usize { - self.name.len() + 1 - + self.query.len() + 1 - + 2 // number of params - + self.data_types().len() * 4 - + 4 // len - + 1 // code + self.name.len() + self.query.len() + self.data_types.len() + 5 } /// New anonymous prepared statement. #[cfg(test)] pub fn new_anonymous(query: &str) -> Self { Self { - name: Arc::new("".into()), - query: Arc::new(query.to_string()), - data_types: Arc::new(vec![]), + name: Bytes::from("\0"), + query: Bytes::from(query.to_owned() + "\0"), + data_types: Bytes::copy_from_slice(&0i16.to_be_bytes()), + original: None, } } /// New prepared statement. pub fn named(name: impl ToString, query: impl ToString) -> Self { Self { - name: Arc::new(name.to_string()), - query: Arc::new(query.to_string()), - data_types: Arc::new(vec![]), + name: Bytes::from(name.to_string() + "\0"), + query: Bytes::from(query.to_string() + "\0"), + data_types: Bytes::copy_from_slice(&0i16.to_be_bytes()), + original: None, } } /// Anonymous prepared statement. pub fn anonymous(&self) -> bool { - self.name.is_empty() + self.name.len() == 1 // Just the null byte. } pub fn query(&self) -> &str { - &self.query + // SAFETY: We check that this is valid UTF-8 in Self::from_bytes. + unsafe { from_utf8_unchecked(&self.query[0..self.query.len() - 1]) } } /// Get query reference. - pub fn query_ref(&self) -> Arc { + pub fn query_ref(&self) -> Bytes { self.query.clone() } pub fn name(&self) -> &str { - &self.name + // SAFETY: We check that this is valid UTF-8 in Self::from_bytes. + unsafe { from_utf8_unchecked(&self.name[0..self.name.len() - 1]) } } pub fn rename(&self, name: &str) -> Parse { let mut parse = self.clone(); - parse.name = Arc::new(name.to_owned()); + parse.name = Bytes::from(name.to_string() + "\0"); + parse.original = None; parse } - pub fn data_types(&self) -> &[i32] { - &self.data_types + pub fn data_types(&self) -> DataTypesIter<'_> { + DataTypesIter { + data_types: &self.data_types, + offset: 0, + } } - pub fn data_types_ref(&self) -> Arc> { + pub fn data_types_ref(&self) -> Bytes { self.data_types.clone() } } +#[derive(Debug)] +pub struct DataTypesIter<'a> { + data_types: &'a Bytes, + offset: usize, +} + +impl DataTypesIter<'_> { + pub fn len(&self) -> usize { + (self.data_types.len() - size_of::()) / size_of::() + } +} + +impl Iterator for DataTypesIter<'_> { + type Item = i32; + + fn next(&mut self) -> Option { + let pos = self.offset * size_of::() + size_of::(); + self.offset += 1; + let mut cursor = Cursor::new(self.data_types); + cursor.advance(pos); + + if cursor.remaining() >= size_of::() { + Some(cursor.get_i32()) + } else { + None + } + } +} + impl FromBytes for Parse { fn from_bytes(mut bytes: Bytes) -> Result { + let original = bytes.clone(); code!(bytes, 'P'); let _len = bytes.get_i32(); - let name = c_string_buf(&mut bytes); - let query = c_string_buf(&mut bytes); - let params = bytes.get_i16() as usize; - let data_types = (0..params).map(|_| bytes.get_i32()).collect::>(); + let name_len = c_string_buf_len(&bytes); + let name = bytes.split_to(name_len); + let query_len = c_string_buf_len(&bytes); + let query = bytes.split_to(query_len); + let data_types = bytes; + + // Validate we got valid UTF-8. + from_utf8(&name[0..name.len() - 1])?; + from_utf8(&query[0..query.len() - 1])?; Ok(Self { - name: Arc::new(name), - query: Arc::new(query), - data_types: Arc::new(data_types), + name, + query, + data_types, + original: Some(original), }) } } impl ToBytes for Parse { fn to_bytes(&self) -> Result { - let mut payload = Payload::named(self.code()); + // Fast path when the contents haven't been changed. + if let Some(ref original) = self.original { + return Ok(original.clone()); + } - payload.put_string(&self.name); - payload.put_string(&self.query); - payload.put_i16(self.data_types.len() as i16); + let mut payload = Payload::named(self.code()); + payload.reserve(self.len()); - for type_ in self.data_types() { - payload.put_i32(*type_); - } + payload.put(self.name.clone()); + payload.put(self.query.clone()); + payload.put(self.data_types.clone()); Ok(payload.freeze()) } @@ -120,6 +177,8 @@ impl Protocol for Parse { #[cfg(test)] mod test { + use bytes::BytesMut; + use super::*; #[test] @@ -128,4 +187,40 @@ mod test { let b = parse.to_bytes().unwrap(); assert_eq!(parse.len(), b.len()); } + + #[test] + fn test_parse_from_bytes() { + let mut parse = Parse::named("__pgdog_1", "SELECT * FROM users"); + let mut data_types = BytesMut::new(); + data_types.put_i16(3); + data_types.put_i32(1); + data_types.put_i32(2); + data_types.put_i32(3); + parse.data_types = data_types.freeze(); + + let iter = parse.data_types(); + assert_eq!(iter.len(), 3); + for (i, v) in iter.enumerate() { + assert_eq!(i as i32 + 1, v); + } + + assert_eq!(parse.name(), "__pgdog_1"); + assert_eq!(parse.query(), "SELECT * FROM users"); + assert_eq!(&parse.query[..], b"SELECT * FROM users\0"); + assert_eq!(&parse.name[..], b"__pgdog_1\0"); + assert_eq!(parse.to_bytes().unwrap().len(), parse.len()); + + let mut b = BytesMut::new(); + b.put_u8(b'P'); + b.put_i32(0); // Doesn't matter + b.put(Bytes::from("__pgdog_1\0")); + b.put(Bytes::from("SELECT * FROM users\0")); + b.put_i16(0); + let parse = Parse::from_bytes(b.freeze()).unwrap(); + assert_eq!(parse.name(), "__pgdog_1"); + assert_eq!(parse.query(), "SELECT * FROM users"); + assert_eq!(parse.data_types().len(), 0); + + assert!(Parse::new_anonymous("SELECT 1").anonymous()); + } } diff --git a/pgdog/src/net/messages/payload.rs b/pgdog/src/net/messages/payload.rs index 2f3260e3..bda4513d 100644 --- a/pgdog/src/net/messages/payload.rs +++ b/pgdog/src/net/messages/payload.rs @@ -27,6 +27,10 @@ impl Payload { } } + pub(crate) fn reserve(&mut self, capacity: usize) { + self.bytes.reserve(capacity); + } + /// Create new named payload. pub fn named(name: char) -> Self { Self { @@ -53,6 +57,7 @@ impl Payload { /// Add a C-style string to the payload. It will be NULL-terminated /// automatically. pub fn put_string(&mut self, string: &str) { + self.bytes.reserve(string.len() + 1); self.bytes.put_slice(string.as_bytes()); self.bytes.put_u8(0); } @@ -74,13 +79,17 @@ impl DerefMut for Payload { impl super::ToBytes for Payload { fn to_bytes(&self) -> Result { - let mut buf = BytesMut::new(); let len = if self.with_len { Some(self.bytes.len() as i32 + 4) // self } else { None }; + let mut buf = BytesMut::with_capacity(match len { + Some(len) => len as usize + 5, + None => 15, + }); + if let Some(name) = self.name { buf.put_u8(name as u8); } diff --git a/pgdog/src/net/messages/query.rs b/pgdog/src/net/messages/query.rs index c7d0f0fd..d327b7d9 100644 --- a/pgdog/src/net/messages/query.rs +++ b/pgdog/src/net/messages/query.rs @@ -61,6 +61,12 @@ impl Protocol for Query { } } +impl From for Query { + fn from(value: T) -> Self { + Query::new(value) + } +} + #[cfg(test)] mod test { use super::*; diff --git a/pgdog/src/net/mod.rs b/pgdog/src/net/mod.rs index 3cc55621..e163b25a 100644 --- a/pgdog/src/net/mod.rs +++ b/pgdog/src/net/mod.rs @@ -7,7 +7,7 @@ pub mod stream; pub mod tls; pub mod tweaks; -use bytes::Buf; +use bytes::{Buf, Bytes}; pub use decoder::Decoder; pub use error::Error; pub use messages::*; @@ -50,8 +50,9 @@ pub async fn c_string(stream: &mut (impl AsyncRead + Unpin)) -> Result String { - let mut result = String::new(); +pub fn c_string_buf(buf: &mut Bytes) -> String { + let len = c_string_buf_len(&buf[..]); + let mut result = String::with_capacity(len); while buf.remaining() > 0 { let c = buf.get_u8(); diff --git a/pgdog/src/net/parameter.rs b/pgdog/src/net/parameter.rs index 5430eff0..19942274 100644 --- a/pgdog/src/net/parameter.rs +++ b/pgdog/src/net/parameter.rs @@ -1,13 +1,25 @@ //! Startup parameter. use std::{ - collections::HashMap, + collections::BTreeMap, + fmt::Display, + hash::{DefaultHasher, Hash, Hasher}, ops::{Deref, DerefMut}, }; +use once_cell::sync::Lazy; + use super::{messages::Query, Error}; -static IMMUTABLE_PARAMS: &[&str] = &["database", "user", "client_encoding"]; +static IMMUTABLE_PARAMS: Lazy> = Lazy::new(|| { + Vec::from([ + String::from("database"), + String::from("user"), + String::from("client_encoding"), + ]) +}); + +// static IMMUTABLE_PARAMS: &[&str] = &["database", "user", "client_encoding"]; /// Startup parameter. #[derive(Debug, Clone, PartialEq)] @@ -33,62 +45,128 @@ pub struct MergeResult { pub changed_params: usize, } +#[derive(Debug, Clone, Hash, PartialEq)] +pub enum ParameterValue { + String(String), + Tuple(Vec), +} + +impl Display for ParameterValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::String(s) => write!(f, "'{}'", s), + Self::Tuple(t) => write!( + f, + "{}", + t.iter() + .map(|s| format!("'{}'", s)) + .collect::>() + .join(", ") + ), + } + } +} + +impl From<&str> for ParameterValue { + fn from(value: &str) -> Self { + Self::String(value.to_string()) + } +} + +impl From for ParameterValue { + fn from(value: String) -> Self { + Self::String(value) + } +} + +impl ParameterValue { + pub fn as_str(&self) -> Option<&str> { + match self { + Self::String(s) => Some(s.as_str()), + _ => None, + } + } +} + /// List of parameters. #[derive(Default, Debug, Clone, PartialEq)] pub struct Parameters { - params: HashMap, + params: BTreeMap, + hash: u64, +} + +impl From> for Parameters { + fn from(value: BTreeMap) -> Self { + let hash = Self::compute_hash(&value); + Self { + params: value, + hash, + } + } } impl Parameters { /// Lowercase all param names. - pub fn insert(&mut self, name: impl ToString, value: impl ToString) -> Option { + pub fn insert( + &mut self, + name: impl ToString, + value: impl Into, + ) -> Option { let name = name.to_string().to_lowercase(); - self.params.insert(name, value.to_string()) + let result = self.params.insert(name, value.into()); + + self.hash = Self::compute_hash(&self.params); + + result } - /// Merge params from self into other, generating the queries - /// needed to sync that state on the server. - pub fn merge(&self, other: &mut Self) -> MergeResult { - let mut different = vec![]; - // let mut reset_to_default = vec![]; - for (k, v) in &self.params { - if IMMUTABLE_PARAMS.contains(&k.as_str()) { + fn compute_hash(params: &BTreeMap) -> u64 { + let mut hasher = DefaultHasher::new(); + + for (k, v) in params { + if IMMUTABLE_PARAMS.contains(k) { continue; } - if let Some(other) = other.get(k) { - if v != other { - different.push((k, v)); - } - } else { - different.push((k, v)); - } - } - for (k, v) in &different { - other.insert(k.to_string(), v.to_string()); + k.hash(&mut hasher); + v.hash(&mut hasher); } - let queries = if different.is_empty() { - vec![] - } else { - let mut queries = vec![]; + hasher.finish() + } - for (k, v) in different { - queries.push(Query::new(format!(r#"SET "{}" TO '{}'"#, k, v))); - } + pub fn tracked(&self) -> Parameters { + self.params + .iter() + .filter(|(k, _)| !IMMUTABLE_PARAMS.contains(k)) + .map(|(k, v)| (k.clone(), v.clone())) + .collect::>() + .into() + } + + /// Merge params from self into other, generating the queries + /// needed to sync that state on the server. + pub fn identical(&self, other: &Self) -> bool { + self.hash == other.hash + } - queries - }; + pub fn set_queries(&self) -> Vec { + self.params + .iter() + .map(|(name, value)| Query::new(format!(r#"SET "{}" TO {}"#, name, value))) + .collect() + } - MergeResult { - changed_params: if queries.is_empty() { 0 } else { queries.len() }, - queries, - } + pub fn reset_queries(&self) -> Vec { + self.params + .keys() + .map(|name| Query::new(format!(r#"RESET "{}""#, name))) + .collect() } /// Get self-declared shard number. pub fn shard(&self) -> Option { - if let Some(application_name) = self.get("application_name") { + if let Some(ParameterValue::String(application_name)) = self.get("application_name") { if application_name.starts_with("pgdog_shard_") { application_name .replace("pgdog_shard_", "") @@ -105,18 +183,19 @@ impl Parameters { /// Get parameter value or returned an error. pub fn get_required(&self, name: &str) -> Result<&str, Error> { self.get(name) - .map(|s| s.as_str()) + .and_then(|s| s.as_str()) .ok_or(Error::MissingParameter(name.into())) } /// Get parameter value or returned a default value if it doesn't exist. pub fn get_default<'a>(&'a self, name: &str, default_value: &'a str) -> &'a str { - self.get(name).map_or(default_value, |p| p) + self.get(name) + .map_or(default_value, |p| p.as_str().unwrap_or(default_value)) } } impl Deref for Parameters { - type Target = HashMap; + type Target = BTreeMap; fn deref(&self) -> &Self::Target { &self.params @@ -131,9 +210,12 @@ impl DerefMut for Parameters { impl From> for Parameters { fn from(value: Vec) -> Self { - Self { - params: value.into_iter().map(|p| (p.name, p.value)).collect(), - } + let params = value + .into_iter() + .map(|p| (p.name, ParameterValue::String(p.value))) + .collect::>(); + let hash = Self::compute_hash(¶ms); + Self { params, hash } } } @@ -153,22 +235,26 @@ impl From<&Parameters> for Vec { #[cfg(test)] mod test { + use crate::net::parameter::ParameterValue; + use super::Parameters; #[test] - fn test_merge() { + fn test_identical() { let mut me = Parameters::default(); me.insert("application_name", "something"); me.insert("TimeZone", "UTC"); + me.insert( + "search_path", + ParameterValue::Tuple(vec!["$user".into(), "public".into()]), + ); let mut other = Parameters::default(); other.insert("TimeZone", "UTC"); - let diff = me.merge(&mut other); - assert_eq!(diff.changed_params, 1); - assert_eq!( - diff.queries[0].query(), - r#"SET "application_name" TO 'something'"# - ); + let same = me.identical(&other); + assert!(!same); + + assert!(Parameters::default().identical(&Parameters::default())); } } diff --git a/pgdog/src/net/stream.rs b/pgdog/src/net/stream.rs index 1356d5cc..2bef06b9 100644 --- a/pgdog/src/net/stream.rs +++ b/pgdog/src/net/stream.rs @@ -97,6 +97,17 @@ impl Stream { } } + /// Check socket is okay while we wait for something else. + pub async fn check(&mut self) -> Result<(), crate::net::Error> { + let mut buf = [0u8; 1]; + match self { + Self::Plain(plain) => plain.get_mut().peek(&mut buf).await?, + Self::Tls(tls) => tls.get_mut().get_mut().0.peek(&mut buf).await?, + }; + + Ok(()) + } + /// Send data via the stream. /// /// # Performance @@ -113,6 +124,7 @@ impl Stream { #[cfg(debug_assertions)] { + trace!(">>> {:?} [{:?}]", message.message()?, self.peer_addr()); use crate::net::messages::FromBytes; use tracing::error; @@ -167,21 +179,34 @@ impl Stream { /// one memory allocation per protocol message. It can be optimized to re-use an existing /// buffer but it's not worth the complexity. pub async fn read(&mut self) -> Result { + let mut buf = BytesMut::with_capacity(5); + self.read_buf(&mut buf).await + } + + /// Read data into a buffer, avoiding unnecessary allocations. + pub async fn read_buf(&mut self, bytes: &mut BytesMut) -> Result { let code = self.read_u8().await?; let len = self.read_i32().await?; - let mut bytes = BytesMut::with_capacity(len as usize + 1); - bytes.put_u8(code); bytes.put_i32(len); - bytes.resize(len as usize + 1, 0); // self + 1 byte for the message code + // Length must be at least 4 bytes. + if len < 4 { + return Err(crate::net::Error::Eof); + } - self.read_exact(&mut bytes[5..]).await?; + let capacity = len as usize + 1; + bytes.reserve(capacity); // self + 1 byte for the message code + unsafe { + // SAFETY: We reserved the memory above, so it's there. + // It contains garbage but we're about to write to it. + bytes.set_len(capacity); + } - let message = Message::new(bytes.freeze()); + self.read_exact(&mut bytes[5..capacity]).await?; - // trace!("📡 => {}", message.code()); + let message = Message::new(bytes.split().freeze()); Ok(message) } diff --git a/pgdog/src/state.rs b/pgdog/src/state.rs index b67947dc..765d7d0d 100644 --- a/pgdog/src/state.rs +++ b/pgdog/src/state.rs @@ -22,6 +22,12 @@ pub enum State { ParseComplete, /// Prepared statement error. PreparedStatementError, + /// Processing server reply. + ReceivingData, + /// Copy started + CopyMode, + /// Just close the connection. + ForceClose, } impl std::fmt::Display for State { @@ -37,6 +43,9 @@ impl std::fmt::Display for State { Error => write!(f, "error"), ParseComplete => write!(f, "parse complete"), PreparedStatementError => write!(f, "prepared statement error"), + ReceivingData => write!(f, "receiving data"), + CopyMode => write!(f, "copy mode"), + ForceClose => write!(f, "force close"), } } } diff --git a/pgdog/src/stats/logger.rs b/pgdog/src/stats/logger.rs new file mode 100644 index 00000000..1c371554 --- /dev/null +++ b/pgdog/src/stats/logger.rs @@ -0,0 +1,45 @@ +use std::{sync::Arc, time::Duration}; + +use tokio::{select, spawn, sync::Notify, time::sleep}; +use tracing::info; + +use crate::frontend::router::parser::Cache; + +#[derive(Debug, Clone)] +pub struct Logger { + interval: Duration, + shutdown: Arc, +} + +impl Logger { + pub fn new() -> Self { + Self { + interval: Duration::from_secs(10), + shutdown: Arc::new(Notify::new()), + } + } + + pub fn shutdown(&self) { + self.shutdown.notify_one(); + } + + pub fn spawn(&self) { + let me = self.clone(); + + spawn(async move { + loop { + select! { + _ = sleep(me.interval) => { + let stats = Cache::stats(); + + info!( + "[query cache stats] direct: {}, multi: {}, hits: {}, misses: {}, size: {}, direct hit rate: {:.3}%", + stats.direct, stats.multi, stats.hits, stats.misses, stats.size, (stats.direct as f64 / std::cmp::max(stats.direct + stats.multi, 1) as f64 * 100.0) + ); + } + _ = me.shutdown.notified() => break, + } + } + }); + } +} diff --git a/pgdog/src/stats/mod.rs b/pgdog/src/stats/mod.rs index 794ff1a2..097734d2 100644 --- a/pgdog/src/stats/mod.rs +++ b/pgdog/src/stats/mod.rs @@ -4,8 +4,10 @@ pub mod http_server; pub mod open_metric; pub mod pools; pub use open_metric::*; +pub mod logger; pub mod query_cache; pub use clients::Clients; +pub use logger::Logger as StatsLogger; pub use pools::{PoolMetric, Pools}; pub use query_cache::QueryCache; diff --git a/pgdog/src/stats/pools.rs b/pgdog/src/stats/pools.rs index 8aeefdeb..751b5fac 100644 --- a/pgdog/src/stats/pools.rs +++ b/pgdog/src/stats/pools.rs @@ -150,22 +150,22 @@ impl Pools { total_xact_time.push(Measurement { labels: labels.clone(), - measurement: totals.xact_time.into(), + measurement: totals.xact_time.as_millis().into(), }); avg_xact_time.push(Measurement { labels: labels.clone(), - measurement: averages.xact_time.into(), + measurement: averages.xact_time.as_millis().into(), }); total_query_time.push(Measurement { labels: labels.clone(), - measurement: totals.query_time.into(), + measurement: totals.query_time.as_millis().into(), }); avg_query_time.push(Measurement { labels: labels.clone(), - measurement: averages.query_time.into(), + measurement: averages.query_time.as_millis().into(), }); } } diff --git a/pgdog/src/util.rs b/pgdog/src/util.rs index 6298d4b2..4a00c5af 100644 --- a/pgdog/src/util.rs +++ b/pgdog/src/util.rs @@ -61,6 +61,7 @@ pub fn random_string(n: usize) -> String { #[cfg(test)] mod test { + use super::*; #[test] diff --git a/pgdog/tests/pgbench-select-1.sql b/pgdog/tests/pgbench-select-1.sql new file mode 100644 index 00000000..8720423b --- /dev/null +++ b/pgdog/tests/pgbench-select-1.sql @@ -0,0 +1,3 @@ +\set id (1021 * random(1, 10000000)) + +SELECT :id; diff --git a/pgdog/tests/pgbench.sh b/pgdog/tests/pgbench.sh index 8fb93528..4fefd427 100644 --- a/pgdog/tests/pgbench.sh +++ b/pgdog/tests/pgbench.sh @@ -2,5 +2,6 @@ # # pgBench test run. # -PGPASSWORD=pgdog pgbench -i -h 127.0.0.1 -p 6432 -U pgdog pgdog -PGPASSWORD=pgdog pgbench -P 1 -h 127.0.0.1 -p 6432 -U pgdog pgdog -c 10 -t 100000 -S --protocol prepared +export PGPORT=${1:-6432} +PGPASSWORD=pgdog pgbench -i -h 127.0.0.1 -U pgdog pgdog +PGPASSWORD=pgdog pgbench -P 1 -h 127.0.0.1 -U pgdog pgdog -c 20 -t 1000000 --protocol extended -S diff --git a/pgdog/tests/pgbouncer/pgbouncer.ini b/pgdog/tests/pgbouncer/pgbouncer.ini index 261393f2..45cecf27 100644 --- a/pgdog/tests/pgbouncer/pgbouncer.ini +++ b/pgdog/tests/pgbouncer/pgbouncer.ini @@ -4,6 +4,8 @@ listen_port = 6433 pool_mode = transaction default_pool_size = 10 auth_file = userlist.txt +max_client_conn = 10000 +min_pool_size = 10 [databases] pgdog = host=127.0.0.1 port=5432 user=pgdog password=pgdog diff --git a/pgdog/tests/pgbouncer/pgdog.toml b/pgdog/tests/pgbouncer/pgdog.toml index 6460bea3..d128ab51 100644 --- a/pgdog/tests/pgbouncer/pgdog.toml +++ b/pgdog/tests/pgbouncer/pgdog.toml @@ -1,5 +1,7 @@ [general] prepared_statements = "disabled" +workers = 2 +min_pool_size = 0 [[databases]] name = "pgdog" diff --git a/users.toml b/users.toml index 592ad4de..1603b71b 100644 --- a/users.toml +++ b/users.toml @@ -1,37 +1,12 @@ -# Basic users configuration. -# -# Two users: # -# - pgdog: in transaction mode, default settings -# - pgdog_session: in session mode, other settings are default +# Basic users configuration. # [[users]] name = "pgdog" database = "pgdog" password = "pgdog" -[[users]] -name = "pgdog_replication" -database = "pgdog" -password = "pgdog" -server_user = "pgdog" -replication_mode = true -min_pool_size = 0 - -[[users]] -name = "pgdog_session" -database = "pgdog" -password = "pgdog" -server_user = "pgdog" -pooler_mode = "session" -min_pool_size = 0 - [[users]] name = "pgdog" database = "pgdog_sharded" password = "pgdog" - -[[users]] -name = "pgdog" -database = "failover" -password = "pgdog"