feat: Query profiling feature#1221
Conversation
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
The merge caused generated files to have a diff. The diff should not be in the PR.
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.
This reverts commit 040d0a5.
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.
src/query.ts
Outdated
| resultsReturned?: number; | ||
| executionDuration?: google.protobuf.IDuration; | ||
| readOperations?: number; | ||
| debugStats?: JSONValue; |
There was a problem hiding this comment.
in Java we made this a Map. Is there a reason why we are using this specific type?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
I think that works, would like a NodeJS opinion however :)
| } | ||
| export interface ExecutionStats { | ||
| resultsReturned?: number; | ||
| executionDuration?: google.protobuf.IDuration; |
There was a problem hiding this comment.
similar here, could this just be a numeric value? Are there other already modeled fields that are similar? What are their return types?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
sg, would appreciate @sofisl's thoughts on this as well :)
There was a problem hiding this comment.
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.
package.json
Outdated
| "extend": "^3.0.2", | ||
| "google-gax": "^4.0.5", | ||
| "is": "^3.3.0", | ||
| "proto3-json-serializer": "^2.0.1", |
There was a problem hiding this comment.
These are pretty big additions. We use protobufjs & proto3-json-serializer in google-gax, is it possible to just use it from there?
There was a problem hiding this comment.
Yes. Great suggestion.
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.