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

Open
wants to merge 55 commits into
base: master
Choose a base branch
from

Conversation

robstradling
Copy link

@robstradling robstradling commented Oct 8, 2024

This PR is based on Trillian's existing MySQL quota manager and storage backend. The first several commits were auto-generated by this script, which forked the existing MySQL code into different directories (whilst preserving the git history) and then did a bunch of search'n'replacing to switch from the database/sql interface to the jackc/pgx interface.

Improving performance is my main reason for using the pgx interface directly. In particular, the pgx interface has allowed me to use PostgreSQL's COPY interface for fast bulk-upserts.

My motivations for putting together this PR are that (1) I and my colleagues at Sectigo have a fair amount of experience with PostgreSQL, but almost no experience with MySQL/MariaDB; and (2) we suffered a CT log failure earlier this year due to MariaDB corruption after disk space exhaustion, and we are confident that PostgreSQL would not have broken under the same circumstances.

Checklist

@roger2hk
Copy link
Contributor

roger2hk commented Oct 8, 2024

/gcbrun

@mhutchinson
Copy link
Contributor

/gcbrun

@mhutchinson
Copy link
Contributor

/gcbrun

@roger2hk
Copy link
Contributor

/gcbrun

@mhutchinson
Copy link
Contributor

/gcbrun

@roger2hk
Copy link
Contributor

/gcbrun

@mhutchinson
Copy link
Contributor

/gcbrun

@robstradling robstradling marked this pull request as ready for review October 29, 2024 14:16
@robstradling robstradling requested a review from a team as a code owner October 29, 2024 14:16
@mhutchinson mhutchinson changed the title WIP: PostgreSQL quota manager and storage backend PostgreSQL quota manager and storage backend Oct 30, 2024
@mhutchinson mhutchinson self-requested a review October 30, 2024 10:44
@mhutchinson mhutchinson self-assigned this Oct 30, 2024
Copy link
Contributor

@mhutchinson mhutchinson left a comment

Choose a reason for hiding this comment

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

Looking great @robstradling. I've reviewed up to the meaty bits. Looking good so far. A few nitty comments, and then a request for some brief docs to help me understand the flows in the storage layers. Once that's done (and I've had my lunch) I can take a look over the remaining files.

.github/workflows/test_pgdb.yaml Show resolved Hide resolved
@@ -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
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

quota/postgresqlqm/postgresql_quota.go Outdated Show resolved Hide resolved
Comment on lines 51 to 53
// 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.
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest moving this to be the second paragraph and expanding it. Other quota managers support features that this doesn't (which is fair enough), but I think should be called out more explicitly and up-front. i.e global only means:

  • no tree specific quotas
  • no limiting based on intermediary certs
  • etc

Phrased another way: this quota manager 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-intermediary, or any other dimension.

Copy link
Author

Choose a reason for hiding this comment

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

FWIW, this comment was copied directly from quota/mysqlqm/mysql_quota.go.
I'm not familiar with any of the quota managers that offer features that this one doesn't, but I've added text (based heavily on your comment) in 32096c4.

storage/postgresql/admin_storage.go Outdated Show resolved Hide resolved
newTree.TreeId,
newTree.TreeState.String(),
newTree.TreeType.String(),
"RFC6962_SHA256", // Unused, filling in for backward compatibility.
Copy link
Contributor

Choose a reason for hiding this comment

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

For all of these unused/backwards compatible fields, you could simply remove them from the table definition and all the queries. You possibly need to pop them into the protos that get returned, but you don't need them in the schema and DB query level.

It seems a bit unfortunate to be writing a new implementation that carries a legacy burden that isn't needed, but if you're aiming for a minimum diff with MySQL then having them in the DB is fine. Either way, you're the maintainer of this code 🙃

Copy link
Author

Choose a reason for hiding this comment

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

Addressed by 917f362.

storage/postgresql/admin_storage.go Outdated Show resolved Hide resolved
Comment on lines +45 to +55
createTempQueueLeavesTable = "CREATE TEMP TABLE TempQueueLeaves (" +
" TreeId BIGINT," +
" LeafIdentityHash BYTEA," +
" LeafValue BYTEA," +
" ExtraData BYTEA," +
" MerkleLeafHash BYTEA," +
" QueueTimestampNanos BIGINT," +
" QueueID BYTEA," +
" IsDuplicate BOOLEAN DEFAULT FALSE" +
") ON COMMIT DROP"
queueLeavesSQL = "SELECT * FROM queue_leaves()"
Copy link
Contributor

Choose a reason for hiding this comment

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

Given enough time I can probably chip away at the layers here to understand what's going on. But it strikes me that what would be super handy is a high level guide in a README.md in this directory that lays out the approach you're taking. If someone were to come and look at this code, how should they start to understand what goes in the temporary tables, the real tables, or the stored procedures? Are the temporary tables bound to a single transaction? Why are stored procedures used rather than direct queries?

I can guess answers to the above with a reasonable degree of accuracy I expect. But I'd feel much more at home if I didn't have to guess 😄 I don't expect this to be a massive tome. Just a couple of paragraphs to explain the approach and perspective you had in mind when this was written will be ace.

Copy link
Author

Choose a reason for hiding this comment

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

Addressed by 8c40e33.

@roger2hk
Copy link
Contributor

/gcbrun

@mhutchinson
Copy link
Contributor

/gcbrun

@mhutchinson
Copy link
Contributor

/gcbrun

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants