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

feat: Query profiling feature #1221

Merged
merged 97 commits into from
May 9, 2024

Conversation

danieljbruce
Copy link
Contributor

@danieljbruce danieljbruce commented Jan 12, 2024

This PR implements Query Profiling in Node Datastore.

Changes:

Two dependencies are imported that are used for decoding structs contained in query profiling explain metrics into a flatter format that matches other clients.

A getInfoFromStats function is added that translates the explain metrics from the server into a format that the user will see. A query mode enum is added and offered to the user. Interfaces are added for explain metrics, the plan and the execution stats. runAggregationQuery and runQuery functions are modified to send info back to the user that contains explain metrics. System tests and unit tests are added as well.

Not included:

Note that this PR does not include query profiling samples. Samples must be included in a separate PR because the samples use require('@google-cloud/datastore') which fetches the latest released version of the client library. Therefore, we must release the query profiling feature first before query profiling samples will work in this PR because we are following the convention other samples follow where the latest release is used for samples.

Copy paste over the files from the preview branch
Thread the query mode through the client library. Allow calls to get made using the query mode.
This code allows basic query profiling to work and creates a basic code snippet that can be used to make it work.
This will be useful for debugging grpc issues.
This mock server will be super useful for ensuring that the right data gets transmitted in private preview so that we can confirm the client library is working correctly.
We use the ts file instead.
See if Explain gets passed along to the mock server.
Protos.json is needed to pass the plan along.
Make sure changes don’t break the use of this callback by adding this test.
Define it with a more general data structure.
…into query-profiling-feature

# Conflicts:
#	protos/google/datastore/v1/query_profile.proto
#	protos/protos.d.ts
#	protos/protos.js
#	protos/protos.json
#	src/v1/datastore_client.ts
@product-auto-label product-auto-label bot added size: xl Pull request size is extra large. api: datastore Issues related to the googleapis/nodejs-datastore API. labels Jan 12, 2024
The merge caused generated files to have a diff. The diff should not be in the PR.
@product-auto-label product-auto-label bot added size: m Pull request size is medium. and removed size: xl Pull request size is extra large. labels Jan 12, 2024
only should not be used here
Data structures need to be added for the return values that contain stats.
Add stats to info if it is available. If there are no results then end the stream and send the info back. This way, stats will always be sent in info if they are available and the program won ’t break if there are no results.
Explain what happens when the result set is empty. Just send the stats back.
The mock server code was used for debugging and now we don’t need it since the service is working.
Calls to nightly don’t have a second database to work with. Regular calls work now so nightly calls are not necessary.
Bring the query profiling tests back.
Stats do not necessarily come from the server.
Each query profiling mode needs to be explored.
Stats returned needs to be parsed by a special library that will remove the complexities of the Struct object.
A library is needed for parsing the Struct values. Add the libraries and use them.
@danieljbruce danieljbruce requested a review from bhshkh April 19, 2024 13:46
src/query.ts Outdated
resultsReturned?: number;
executionDuration?: google.protobuf.IDuration;
readOperations?: number;
debugStats?: JSONValue;
Copy link
Contributor

Choose a reason for hiding this comment

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

in Java we made this a Map. Is there a reason why we are using this specific type?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The client library doesn't typically return Map objects. It usually returns dictionaries when an object needs to be returned that maps keys to values. For example, an interface like { [key: string]: any };.

The issue here is that the values coming from the server are of type google.protobuf.IStruct and the serializer.toProto3JSON function is used to decode these types returning a JSONValue type which is stored in debugStats. The compiler only guarantees the value will be a JSONValue, but in practice a { [key: string]: any }; type should always be returned.

We can change the return type to { [key: string]: any }; and the compiler won't complain because we are using Object.assign so maybe we should do that. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that works, would like a NodeJS opinion however :)

}
export interface ExecutionStats {
resultsReturned?: number;
executionDuration?: google.protobuf.IDuration;
Copy link
Contributor

Choose a reason for hiding this comment

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

similar here, could this just be a numeric value? Are there other already modeled fields that are similar? What are their return types?

Copy link
Contributor Author

@danieljbruce danieljbruce Apr 30, 2024

Choose a reason for hiding this comment

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

When a time is provided by the user then just a number representing milliseconds is provided and parsed here to match the proto. However, when commit returns a commitTime then it is passed back to the user as is. go/cfdb-ds-go-query-profiling returns a duration object like this according to the design doc so I think this should stay as is to match Golang and other return values.

Copy link
Contributor

Choose a reason for hiding this comment

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

sg, would appreciate @sofisl's thoughts on this as well :)

Copy link
Contributor

Choose a reason for hiding this comment

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

For both types, I think this is OK given that this is exactly what is returned from the service and what other languages are doing. However as I was mentioning to @danieljbruce, I think it's worth showing users how to transform these values in samples, which will be in a separate PR.

@danieljbruce danieljbruce requested a review from sofisl April 25, 2024 18:32
package.json Outdated
@@ -48,6 +48,8 @@
"extend": "^3.0.2",
"google-gax": "^4.0.5",
"is": "^3.3.0",
"proto3-json-serializer": "^2.0.1",
Copy link
Contributor

Choose a reason for hiding this comment

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

These are pretty big additions. We use protobufjs & proto3-json-serializer in google-gax, is it possible to just use it from there?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. Great suggestion.

@danieljbruce danieljbruce requested review from kolea2 and sofisl May 1, 2024 17:45
@danieljbruce danieljbruce added the owlbot:run Add this label to trigger the Owlbot post processor. label May 9, 2024
@gcf-owl-bot gcf-owl-bot bot removed the owlbot:run Add this label to trigger the Owlbot post processor. label May 9, 2024
@danieljbruce danieljbruce added the kokoro:force-run Add this label to force Kokoro to re-run the tests. label May 9, 2024
@yoshi-kokoro yoshi-kokoro removed the kokoro:force-run Add this label to force Kokoro to re-run the tests. label May 9, 2024
@danieljbruce danieljbruce added the kokoro:force-run Add this label to force Kokoro to re-run the tests. label May 9, 2024
@yoshi-kokoro yoshi-kokoro removed the kokoro:force-run Add this label to force Kokoro to re-run the tests. label May 9, 2024
@danieljbruce danieljbruce added the kokoro:force-run Add this label to force Kokoro to re-run the tests. label May 9, 2024
@yoshi-kokoro yoshi-kokoro removed the kokoro:force-run Add this label to force Kokoro to re-run the tests. label May 9, 2024
@danieljbruce danieljbruce added the owlbot:run Add this label to trigger the Owlbot post processor. label May 9, 2024
@gcf-owl-bot gcf-owl-bot bot removed the owlbot:run Add this label to trigger the Owlbot post processor. label May 9, 2024
@danieljbruce danieljbruce merged commit 414dec4 into googleapis:main May 9, 2024
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: datastore Issues related to the googleapis/nodejs-datastore API. size: l Pull request size is large.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants