-
Notifications
You must be signed in to change notification settings - Fork 102
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
feat: inline BeginTransaction with first statement #1692
Changes from 1 commit
3d06c45
8d5c6d6
15944f5
dd9891e
6b57710
976ee59
154872b
2caaa0f
9929be5
f65e2d1
6d83a94
7eb3831
f9aa221
eeef8cf
4fff842
cfa405e
53f1e1c
e146e89
1b82e78
e5585ff
241394d
fa3c024
c2b2ac6
2f226e1
6d94a86
b0bccf5
346abea
311a80f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -570,7 +570,7 @@ export class Snapshot extends EventEmitter { | |
|
||
if (this.id) { | ||
transaction.id = this.id as Uint8Array; | ||
} else if (typeof this._options.readWrite !== 'undefined') { | ||
} else if (this._options.readWrite) { | ||
transaction.begin = this._options; | ||
} else { | ||
transaction.singleUse = this._options; | ||
|
@@ -615,7 +615,7 @@ export class Snapshot extends EventEmitter { | |
json, | ||
jsonOptions, | ||
maxResumeRetries, | ||
}).on('response', response => { | ||
})?.on('response', response => { | ||
if (response.metadata && response.metadata!.transaction && !this.id) { | ||
this._update(response.metadata!.transaction); | ||
} | ||
|
@@ -1040,7 +1040,7 @@ export class Snapshot extends EventEmitter { | |
const transaction: spannerClient.spanner.v1.ITransactionSelector = {}; | ||
if (this.id) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does not take into account that a transaction could in theory have multiple requests in flight at the same time. If a transaction starts out with sending two Consider the following test case (the it('should only inline one begin transaction', async () => {
const database = newTestDatabase();
await database.runTransactionAsync(async tx => {
const rowCount1 = getRowCountFromStreamingSql(tx, {sql: selectSql});
const rowCount2 = getRowCountFromStreamingSql(tx, {sql: selectSql});
await Promise.all([rowCount1, rowCount2]);
await tx.commit();
});
await database.close();
let request = spannerMock.getRequests().find(val => {
return (val as v1.ExecuteSqlRequest).sql;
}) as v1.ExecuteSqlRequest;
assert.ok(request, 'no ExecuteSqlRequest found');
assert.deepStrictEqual(request.transaction!.begin!.readWrite, {});
assert.strictEqual(request.sql, selectSql);
request = spannerMock
.getRequests()
.slice()
.reverse()
.find(val => {
return (val as v1.ExecuteSqlRequest).sql;
}) as v1.ExecuteSqlRequest;
assert.ok(request, 'no ExecuteSqlRequest found');
assert.strictEqual(request.sql, selectSql);
assert.ok(request.transaction!.id, 'TransactionID is not set.');
const beginTxnRequest = spannerMock.getRequests().find(val => {
return (val as v1.BeginTransactionRequest).options?.readWrite;
}) as v1.BeginTransactionRequest;
assert.ok(!beginTxnRequest, 'beginTransaction was called');
}); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're absolutely right. Added a lock that prevents a multiple inline begin transaction at the same time. Thanks! |
||
transaction.id = this.id as Uint8Array; | ||
} else if (typeof this._options.readWrite !== 'undefined') { | ||
} else if (this._options.readWrite) { | ||
transaction.begin = this._options; | ||
} else { | ||
transaction.singleUse = this._options; | ||
|
@@ -1269,16 +1269,18 @@ export class Snapshot extends EventEmitter { | |
private _wrapWithIdWaiter( | ||
makeRequest: (resumeToken?: ResumeToken) => Readable): | ||
(resumeToken?: ResumeToken) => Readable { | ||
if (this.id || typeof this._options.readWrite === 'undefined') { | ||
if (this.id || !this._options.readWrite) { | ||
return makeRequest; | ||
} | ||
if (!this._inlineBeginStarted) { | ||
this._inlineBeginStarted = true; | ||
return makeRequest; | ||
} | ||
return (resumeToken?: ResumeToken): Readable => | ||
this._idWaiter.once('notify', () => | ||
this._idWaiter.wrap(makeRequest(resumeToken))); | ||
this._idWaiter.once('notify', () => makeRequest(resumeToken) | ||
.on('data', (chunk) => this._idWaiter.emit('data', chunk)) | ||
.once('end', () => this._idWaiter.emit('end')) | ||
); | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind adding a test that verifies the following:
PartialResultSet
s are returned by the stream, with (at least) one of them returning a resume token.UNAVAILABLE
error and the stream is restarted with a resume token.Step 3 should use the transaction ID that was returned by step 1, and not include a
BeginTransaction
option.(https://github.com/googleapis/nodejs-spanner/pull/1253/files is a very old implementation for the same. Some of the tests there might be re-usable.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added. thanks a lot for this comment: it helped to find a bug in the code