Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PostgreSQL quota manager and storage backend #3644

Merged
merged 65 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
21ef4b2
Duplicate MySQL files to new PostgreSQL directories, preserving git l…
robstradling Oct 1, 2024
78653c2
Restore MySQL files
robstradling Oct 1, 2024
9f48d08
Replace 'MySQL' references with 'PostgreSQL', preserving case of each…
robstradling Oct 1, 2024
b0f7dfe
Build the PostgreSQL protobuf definitions
robstradling Oct 1, 2024
18cf306
Rename PostgreSQL 'testdb' package to 'testdbpgx'
robstradling Oct 1, 2024
e01fb0b
Convert from database/sql API to jackc/pgx/v5 API
robstradling Oct 1, 2024
33451e6
Update imports
robstradling Oct 1, 2024
6d88880
Convert schema
robstradling Oct 1, 2024
74526b6
Use EXPLAIN output to estimate rows in PostgreSQL quota.Manager
robstradling Oct 1, 2024
e3583cd
PostgreSQL doesn't have an equivalent of MySQL's strict mode
robstradling Oct 1, 2024
a167577
Context required for pgx Commit() and Rollback() functions
robstradling Oct 1, 2024
c127965
Remove statement map and PrepareContext() calls, because pgx automati…
robstradling Oct 1, 2024
cb7bda2
Use ANY to bind arrays, instead of expanding placeholders
robstradling Oct 1, 2024
52f2867
Use PostgreSQL's COPY interface and a temporary table to upsert subtrees
robstradling Oct 1, 2024
51def32
Use PostgreSQL parameter placeholder syntax
robstradling Oct 1, 2024
22f955a
Format SQL queries consistently and without including unnecessary whi…
robstradling Oct 1, 2024
e8fdc37
Remove explicit delete from TreeControl, because no previous versions…
robstradling Oct 1, 2024
0f6f593
Adapt getVersion query to PostgreSQL
robstradling Oct 1, 2024
10d47f8
Context required for pgx Exec() and Ping() functions
robstradling Oct 1, 2024
e617388
No error returned by pgx RowsAffected() function
robstradling Oct 1, 2024
a1ccf26
Check Rows errors consistently and correctly
robstradling Oct 1, 2024
66d2c7f
Adapt errors.go to PostgreSQL
robstradling Oct 1, 2024
8218303
Adapt connection pool opening to PostgreSQL
robstradling Oct 1, 2024
92030b3
No error returned by pgxpool Close() function
robstradling Oct 1, 2024
f68b8b9
Pass arguments directly to Query in getLeavesByRangeInternal
robstradling Oct 1, 2024
1456b20
Adapt provider.go with plausible postgreSQLURI and drop calls to data…
robstradling Oct 1, 2024
aff11fc
Remove CockroachDB stuff from testdbpgx and specify plausible default…
robstradling Oct 1, 2024
bdd9faf
Tidy up / fix pgx imports
robstradling Oct 1, 2024
7b0ae0a
Plug PostgreSQL storage and quota providers into log_server and log_s…
robstradling Oct 1, 2024
2846d36
Enable the testdbpgx tokenizer to handle PL/pgSQL functions correctly…
robstradling Oct 1, 2024
0121720
To pass postgresql_quota_test requires fresher row estimates, so ANAL…
robstradling Oct 1, 2024
ba74553
PostgreSQL connection strings support TLS natively
robstradling Oct 1, 2024
2c5598f
Rebuild the PostgreSQL protobuf definitions with updated protoc-gen-go
robstradling Oct 1, 2024
b365aed
Use PostgreSQL's COPY interface for updating sequenced leaves
robstradling Oct 2, 2024
aa47b36
CopyFrom seems to require all lower case for table and column names
robstradling Oct 2, 2024
607c13a
Use PostgreSQL's COPY interface and a temporary table to queue leaves…
robstradling Oct 7, 2024
7a0df88
Fix conflict handling in multiple subtree insert query
robstradling Oct 8, 2024
7ce0258
Unmarshal storage settings before beginning transaction in beginTreeT…
robstradling Oct 8, 2024
55f0656
go get -u github.com/jackc/pgx/v5
robstradling Oct 8, 2024
b644630
go get github.com/google/trillian/storage/postgresql/testdbpgx
robstradling Oct 8, 2024
9ecaa58
Deleted all of the revisioned tree support
mhutchinson Oct 10, 2024
8e459da
Missed one
mhutchinson Oct 10, 2024
6698903
Disambiguate flag name
mhutchinson Oct 10, 2024
9c72070
Merge branch 'master' into postgresql_support
robstradling Oct 15, 2024
7c1f8c5
Merge branch 'google:master' into postgresql_support
robstradling Oct 25, 2024
2d5c941
Fix integration and unit tests
robstradling Oct 25, 2024
d1a21e1
Enable the BigBatch tests
robstradling Oct 25, 2024
0eac2ab
Hopefully fix trillian-pr-tests (trillian-opensource-ci) checks
robstradling Oct 28, 2024
965aa91
No need to sortLeavesForInsert
robstradling Oct 29, 2024
651b3b5
Update copyright details
robstradling Oct 30, 2024
72964d2
Remove vestigial Trees.PrivateKey and Trees.PublicKey fields
robstradling Oct 30, 2024
917f362
Remove vestigial Trees.HashStrategy, Trees.HashAlgorithm, and Trees.S…
robstradling Oct 31, 2024
dd85139
Add missing DROP FUNCTIONs.
robstradling Oct 31, 2024
32096c4
Call out the caveats in the quota manager more explicitly and up-front
robstradling Nov 5, 2024
8c40e33
Add a README.md that provides an overview of the PostgreSQL storage i…
robstradling Nov 5, 2024
28df5c0
Cover PostgreSQL in the mitigation for Issue #1297 in CODEOWNERS
robstradling Nov 5, 2024
286e278
Add PostgreSQL storage and quota implementations to the feature imple…
robstradling Nov 5, 2024
a4ee5cd
Full stops
robstradling Nov 5, 2024
1aa5094
Merge branch 'master' into postgresql_support
robstradling Nov 6, 2024
0462f62
Update CHANGELOG.md
robstradling Nov 6, 2024
6e3eb86
Remove Rob from CODEOWNERS
robstradling Nov 6, 2024
d41757e
Transfer PostgreSQL TODOs to Rob
robstradling Nov 6, 2024
378779f
Use the batched queue implementation, and remove the non-batched option
robstradling Nov 6, 2024
8102b6a
Remove vestigial Subtree.SubtreeRevision field
robstradling Nov 6, 2024
be96182
Remove vestigial TreeHead.TreeRevision field
robstradling Nov 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/workflows/test_pgdb.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
name: Test PostgreSQL
on:
push:
branches:
- master
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
lint:
permissions:
contents: read # for actions/checkout to fetch code
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1

- uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
with:
go-version-file: go.mod
check-latest: true
cache: true

- uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
with:
version: 'v1.55.1'
args: ./storage/postgresql

integration-and-unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1

- uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
with:
go-version-file: go.mod
check-latest: true
cache: true

- name: Build before tests
run: go mod download && go build ./...

- name: Run PostgreSQL
run: docker run --rm -d --name=pgsql -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust postgres:latest

- name: Wait for PostgreSQL
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0
with:
timeout_seconds: 15
max_attempts: 3
retry_on: error
command: docker exec pgsql psql -U postgres -c "SELECT 1"

- name: Get PostgreSQL logs
run: docker logs pgsql 2>&1

- name: Run integration tests
run: ./integration/integration_test.sh
env:
TEST_POSTGRESQL_URI: postgresql:///defaultdb?host=localhost&user=postgres&password=postgres
POSTGRESQL_IN_CONTAINER: true
POSTGRESQL_CONTAINER_NAME: pgsql

- name: Run unit tests
mhutchinson marked this conversation as resolved.
Show resolved Hide resolved
run: go test -v ./storage/postgresql/... ./quota/postgresqlqm/...

1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@
Antonio Marcedone <[email protected]>
Google LLC
Internet Security Research Group
Sectigo Limited
Vishal Kuo <[email protected]>
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## HEAD

* Add PostgreSQL quota manager and storage backend by @robstradling in https://github.com/google/trillian/pull/3644

## v1.6.1

* Recommended go version for development: 1.22
Expand Down
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@
# upgrade schema instances.
/storage/mysql/schema/* @mhutchinson @AlCutter
/storage/cloudspanner/spanner.sdl @mhutchinson @AlCutter
/storage/postgresql/schema/* @mhutchinson @AlCutter
1 change: 1 addition & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ Paul Hadfield <[email protected]> <[email protected]>
Pavel Kalinnikov <[email protected]> <[email protected]>
Pierre Phaneuf <[email protected]> <[email protected]>
Rob Percival <[email protected]>
Rob Stradling <[email protected]>
Roger Ng <[email protected]> <[email protected]>
Vishal Kuo <[email protected]>
2 changes: 2 additions & 0 deletions cmd/trillian_log_server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@ import (
_ "github.com/google/trillian/storage/cloudspanner"
_ "github.com/google/trillian/storage/crdb"
_ "github.com/google/trillian/storage/mysql"
_ "github.com/google/trillian/storage/postgresql"
Copy link
Contributor

Choose a reason for hiding this comment

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

You're following the existing pattern which is the right thing to do. However, I think this pattern is kinda suspect in that it leads to pretty massive binaries. This small change here increases the size of the log server binary by another 10%.

❯ ls -l trillian_log_server
.rwxr-xr-x 61M mhutchinson 30 Oct 11:21 trillian_log_server
❯ go build ./cmd/trillian_log_server
❯ ls -l trillian_log_server
.rwxr-xr-x 67M mhutchinson 30 Oct 11:22 trillian_log_server

I don't expect you to make any code changes in this PR in response to this. But I'm squirting a stream of conciousness into this comment as a TODO to at least raise an issue to discuss this. It could be as simple a solution as docs saying that this binary is the swiss army knife, but if you want a svelte version for a particular environment then copy it and remove the other imports.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here's an idea: robstradling#5


// Load quota providers
_ "github.com/google/trillian/quota/crdbqm"
_ "github.com/google/trillian/quota/mysqlqm"
_ "github.com/google/trillian/quota/postgresqlqm"
)

var (
Expand Down
2 changes: 2 additions & 0 deletions cmd/trillian_log_signer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,12 @@ import (
_ "github.com/google/trillian/storage/cloudspanner"
_ "github.com/google/trillian/storage/crdb"
_ "github.com/google/trillian/storage/mysql"
_ "github.com/google/trillian/storage/postgresql"

// Load quota providers
_ "github.com/google/trillian/quota/crdbqm"
_ "github.com/google/trillian/quota/mysqlqm"
_ "github.com/google/trillian/quota/postgresqlqm"
)

var (
Expand Down
8 changes: 8 additions & 0 deletions docs/Feature_Implementation_Matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ The Log storage implementations supporting the original Trillian log.
| CloudSpanner | Beta | | Google maintains continuous-integration environment based on CloudSpanner. |
| MySQL | GA | ✓ | |
| CockroachDB | Alpha | | Supported by [Equinix Metal](https://deploy.equinix.com/). |
| PostgreSQL | Alpha | | Supported by [Rob Stradling](https://github.com/robstradling) at [Sectigo](https://github.com/sectigo). |

##### Spanner
This is a Google-internal implementation, and is used by all of Google's current Trillian deployments.
Expand All @@ -86,6 +87,12 @@ This implementation has been tested with CockroachDB 22.1.10.

It's currently in alpha mode and is not yet in production use.

##### PostgreSQL

This implementation has been tested with PostgreSQL 17.0.

It's currently in alpha mode and is not yet in production use.

### Monitoring

Supported monitoring frameworks, allowing for production monitoring and alerting.
Expand Down Expand Up @@ -115,6 +122,7 @@ Supported frameworks for quota management.
| MySQL | Beta | ? | |
| Redis | Alpha | ✓ | |
| CockroachDB | Alpha | | Supported by [Equinix Metal](https://deploy.equinix.com/). |
| PostgreSQL | Alpha | | Supported by [Rob Stradling](https://github.com/robstradling) at [Sectigo](https://github.com/sectigo). |

### Key management

Expand Down
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ require (
github.com/google/go-cmp v0.6.0
github.com/google/go-licenses/v2 v2.0.0-alpha.1
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438
github.com/jackc/pgx/v5 v5.7.1
github.com/letsencrypt/pkcs11key/v4 v4.0.0
github.com/lib/pq v1.10.9
github.com/prometheus/client_golang v1.20.5
Expand Down Expand Up @@ -107,9 +109,10 @@ require (
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgtype v1.14.3 // indirect
github.com/jackc/pgx/v4 v4.18.3 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jhump/protoreflect v1.16.0 // indirect
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect
github.com/jonboulle/clockwork v0.4.0 // indirect
Expand Down
12 changes: 12 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,8 @@ github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438 h1:Dj0L5fhJ9F82ZJyVOmBx6msDp/kfd1t9GRfny/mfJA0=
github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
Expand All @@ -995,6 +997,8 @@ github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
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/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
Expand All @@ -1009,11 +1013,19 @@ github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgS
github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA=
github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
github.com/jackc/pgx/v5 v5.5.2 h1:iLlpgp4Cp/gC9Xuscl7lFL1PhhW+ZLtXZcrfCt4C3tA=
github.com/jackc/pgx/v5 v5.5.2/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0=
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
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/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg=
github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8=
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY=
Expand Down
5 changes: 5 additions & 0 deletions integration/functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ log_prep_test() {
yes | bash "${TRILLIAN_PATH}/scripts/resetdb.sh"
elif [[ "${TEST_COCKROACHDB_URI}" != "" ]]; then
yes | bash "${TRILLIAN_PATH}/scripts/resetcrdb.sh"
elif [[ "${TEST_POSTGRESQL_URI}" != "" ]]; then
yes | bash "${TRILLIAN_PATH}/scripts/resetpgdb.sh"
fi

local logserver_opts=''
Expand All @@ -139,6 +141,9 @@ log_prep_test() {
elif [[ "${TEST_COCKROACHDB_URI}" != "" ]]; then
logserver_opts+="--quota_system=crdb --storage_system=crdb --crdb_uri=${TEST_COCKROACHDB_URI}"
logsigner_opts+="--quota_system=crdb --storage_system=crdb --crdb_uri=${TEST_COCKROACHDB_URI}"
elif [[ "${TEST_POSTGRESQL_URI}" != "" ]]; then
logserver_opts+="--quota_system=postgresql --storage_system=postgresql --postgresql_uri=${TEST_POSTGRESQL_URI}"
logsigner_opts+="--quota_system=postgresql --storage_system=postgresql --postgresql_uri=${TEST_POSTGRESQL_URI}"
fi

# Start a local etcd instance (if configured).
Expand Down
115 changes: 115 additions & 0 deletions quota/postgresqlqm/postgresql_quota.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright 2024 Trillian Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package postgresqlqm defines a PostgreSQL-based quota.Manager implementation.
package postgresqlqm

import (
"context"
"errors"

"github.com/google/trillian/quota"
"github.com/jackc/pgx/v5/pgxpool"
)

const (
// DefaultMaxUnsequenced is a suggested value for MaxUnsequencedRows.
// Note that this is a Global/Write quota suggestion, so it applies across trees.
DefaultMaxUnsequenced = 500000 // About 2h of non-stop signing at 70QPS.

countFromExplainOutputQuery = "SELECT count_estimate($1)"
countFromUnsequencedQuery = "SELECT COUNT(*) FROM Unsequenced"
)

// ErrTooManyUnsequencedRows is returned when tokens are requested but Unsequenced has grown
// beyond the configured limit.
var ErrTooManyUnsequencedRows = errors.New("too many unsequenced rows")

// QuotaManager is a PostgreSQL-based quota.Manager implementation.
//
// QuotaManager only implements Global/Write quotas, which is based on the number of Unsequenced
// rows (to be exact, tokens = MaxUnsequencedRows - actualUnsequencedRows).
// Other quotas are considered infinite. In other words, it attempts to protect the MMD SLO of all
// logs in the instance, but it does not make any attempt to ensure fairness, whether per-tree,
// per-intermediate-CA (in the case of Certificate Transparency), or any other dimension.
//
// It has two working modes: one estimates the number of Unsequenced rows by collecting information
// from EXPLAIN output; the other does a select count(*) on the Unsequenced table. Estimates are
// default, even though they are approximate, as they're constant time (select count(*) on
// PostgreSQL needs to traverse the index and may take quite a while to complete).
// Other estimation methods exist (see https://wiki.postgresql.org/wiki/Count_estimate), but using
// EXPLAIN output is the most accurate because it "fetches the actual current number of pages in
// the table (this is a cheap operation, not requiring a table scan). If that is different from
// relpages then reltuples is scaled accordingly to arrive at a current number-of-rows estimate."
// (quoting https://www.postgresql.org/docs/current/row-estimation-examples.html)
type QuotaManager struct {
DB *pgxpool.Pool
MaxUnsequencedRows int
UseSelectCount bool
}

// GetTokens implements quota.Manager.GetTokens.
// It doesn't actually reserve or retrieve tokens, instead it allows access based on the number of
// rows in the Unsequenced table.
func (m *QuotaManager) GetTokens(ctx context.Context, numTokens int, specs []quota.Spec) error {
for _, spec := range specs {
if spec.Group != quota.Global || spec.Kind != quota.Write {
continue
}
// Only allow global writes if Unsequenced is under the expected limit
count, err := m.countUnsequenced(ctx)
if err != nil {
return err
}
if count+numTokens > m.MaxUnsequencedRows {
return ErrTooManyUnsequencedRows
}
}
return nil
}

// PutTokens implements quota.Manager.PutTokens.
// It's a noop for QuotaManager.
func (m *QuotaManager) PutTokens(ctx context.Context, numTokens int, specs []quota.Spec) error {
return nil
}

// ResetQuota implements quota.Manager.ResetQuota.
// It's a noop for QuotaManager.
func (m *QuotaManager) ResetQuota(ctx context.Context, specs []quota.Spec) error {
return nil
}

func (m *QuotaManager) countUnsequenced(ctx context.Context) (int, error) {
if m.UseSelectCount {
return countFromTable(ctx, m.DB)
}
return countFromExplainOutput(ctx, m.DB)
}

func countFromExplainOutput(ctx context.Context, db *pgxpool.Pool) (int, error) {
var count int
if err := db.QueryRow(ctx, countFromExplainOutputQuery, "Unsequenced").Scan(&count); err != nil {
return 0, err
}
return count, nil
}

func countFromTable(ctx context.Context, db *pgxpool.Pool) (int, error) {
var count int
if err := db.QueryRow(ctx, countFromUnsequencedQuery).Scan(&count); err != nil {
return 0, err
}
return count, nil
}
Loading
Loading