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

fix: Optimize Transaction PITR #2002

Merged
merged 5 commits into from
Feb 28, 2024

Conversation

tom-andersen
Copy link
Contributor

@tom-andersen tom-andersen commented Feb 23, 2024

For transactions with read time, the begin transaction and commit can be omitted, thereby decreasing latency.

b/324245706

@product-auto-label product-auto-label bot added size: l Pull request size is large. api: firestore Issues related to the googleapis/nodejs-firestore API. labels Feb 23, 2024
@tom-andersen tom-andersen changed the title Optimize Transaction PITR fix: Optimize Transaction PITR Feb 23, 2024
Copy link

conventional-commit-lint-gcf bot commented Feb 23, 2024

🤖 I detect that the PR title and the commit message differ and there's only one commit. To use the PR title for the commit history, you can use Github's automerge feature with squashing, or use automerge label. Good luck human!

-- conventional-commit-lint bot
https://conventionalcommits.org/

@tom-andersen tom-andersen marked this pull request as ready for review February 23, 2024 23:38
@tom-andersen tom-andersen requested review from a team as code owners February 23, 2024 23:38
requestTag: this._requestTag,
})
.then(() => {});
async commit(): Promise<void> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is purely a refactor to use async syntax.

.then(resp => {
this._transactionId = resp.transaction!;
});
const resp = await this._firestore.request<
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is purely a refactor to use async syntax.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks. Nice improvement.

@@ -5319,30 +5319,6 @@ describe('Transaction class', () => {
expect(snapshot.exists).to.be.true;
expect(snapshot.get('foo')).to.equal(1);
});

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added client side exceptions to attempting write on readonly transaction, so this integration test is no longer valid.

@MarkDuckworth MarkDuckworth self-assigned this Feb 28, 2024
Copy link
Contributor

@MarkDuckworth MarkDuckworth left a comment

Choose a reason for hiding this comment

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

Direction looks good. There are a few comments for your consideration.

@@ -265,6 +290,9 @@ export class Transaction implements firestore.Transaction {
documentRef: firestore.DocumentReference<AppModelType, DbModelType>,
data: firestore.WithFieldValue<AppModelType>
): Transaction {
if (this._readOnly) {
throw new Error(READ_ONLY_WRITE_ERROR_MSG);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

There has been a recent movement in the SDKs to leave runtime validation up to the server. In this case, I think performing the validation in the client is acceptable because a read-only transaction should never be writable, that will not change. Calling this out for your consideration.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For ReadTime transactions, we don't call commit which would normally be when backend could respond. So this is less preference, and more technical requirement.

.then(resp => {
this._transactionId = resp.transaction!;
});
const resp = await this._firestore.request<
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks. Nice improvement.

})
.then(() => {});
async commit(): Promise<void> {
if (this._readTime) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to check if the _readOnly flag is set instead of _readTime. The type safety will not guarantee runTransaction will be called for a readOnly transaction without readTime being set.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ReadOnly but without ReadTime are still transactions that have BeginTransaction and Commit request. That is why I have to use _readTime, since only in the subset of cases where the transaction if ReadOnly AND with ReadTime can we do the optimization.

However, this is also a little weird of a check that I added, since this will only occur if there is a bug in SDK. The customer never has an opportunity to call commit() on transactions. Calling commit() is done implicitly when update lambda completes. So this should never happen so long as our SDK logic is correct.

async runTransactionOnce<T>(
updateFunction: (transaction: Transaction) => Promise<T>
): Promise<T> {
if (!this._readTime) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment with respect to using _readOnly vs _readTime

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Again this optimization only works for the subset of ReadOnly transaction that have ReadTime.

);
}
const result = await promise;
if (!this._readTime) {
Copy link
Contributor

Choose a reason for hiding this comment

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

same

Copy link
Contributor Author

Choose a reason for hiding this comment

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

dido

@tom-andersen tom-andersen merged commit 2f08612 into main Feb 28, 2024
18 checks passed
@tom-andersen tom-andersen deleted the tomandersen/transactionReadTimeOptimization branch February 28, 2024 19:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: firestore Issues related to the googleapis/nodejs-firestore API. size: l Pull request size is large.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants