-
Notifications
You must be signed in to change notification settings - Fork 206
datastore: add EnableKeyConversion for compatibility with Cloud Datastore encoded keys #192
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
Conversation
CI fails for Go 1.8, as the new dependencies use type aliasing (and other things) added in 1.9. This looks like another point in favor of more specific code duplication (though I ack the risk of future divergence). |
So there's good news and bad news. 👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there. 😕 The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request. Note to project maintainer: This is a terminal state, meaning the ℹ️ Googlers: Go here for more info. |
1 similar comment
So there's good news and bad news. 👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there. 😕 The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request. Note to project maintainer: This is a terminal state, meaning the ℹ️ Googlers: Go here for more info. |
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.
Looks great overall!
func protoToKey(p *cloudpb.Key) (*Key, error) { | ||
var key *Key | ||
var namespace string | ||
if partition := p.PartitionId; partition != nil { |
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.
Could this be simplified to namespace := p.GetPartitionId().GetNamespaceId()
? Normally, the Get
function for protos handles nil
values nicely.
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.
Everything under internal/cloudkey and internal/cloudpb is copied/pasted from cloud.google.com/go/datastore, we should keep as-is.
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.
Can you make that more clear? I wasn't sure where the copy/paste started & stopped.
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.
Hopefully better now. Added package-level doc, too.
"github.com/golang/protobuf/proto" | ||
) | ||
|
||
// Code below is copied from google.golang.org/genproto/googleapis/datastore/v1 |
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.
Maybe comment on why it was copied?
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.
PTAL at package-level doc.
@@ -254,6 +254,9 @@ func DecodeKey(encoded string) (*Key, error) { | |||
|
|||
ref := new(pb.Reference) | |||
if err := proto.Unmarshal(b, ref); err != nil { | |||
if k := decodeCloudKey(encoded); k != nil { |
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.
Might be worth a comment explaining why this is done this way.
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.
Done
datastore/keycompat.go
Outdated
keyConversion.mu.RLock() | ||
project := keyConversion.project | ||
keyConversion.mu.RUnlock() | ||
return project |
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.
Seems weird to R lock the mutex and return the value... Sounds like it would be easy to have a race condition when the value is used.
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.
Once set, it's immutable and will always return the same value. Will add a comment.
datastore/keycompat.go
Outdated
return project | ||
} | ||
|
||
// decodeCloudKey attempts to decode the given encoded key generated by the Cloud Datastore client library, returning nil if the key couldn't be decoded. |
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.
Reference the full package name rather than "Cloud Datastore client library"?
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.
Done
} | ||
|
||
// decodeCloudKey attempts to decode the given encoded key generated by the Cloud Datastore client library, returning nil if the key couldn't be decoded. | ||
func decodeCloudKey(encoded string) *Key { |
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.
This should probably return an error. Good not to rely on special return values to indicate success/failure (other than an error
).
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.
This was a simplification - we don't use the error value. I think the contract of "non-nil if valid" is fine?
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.
SGTM. Similar to how protos work in general, I suppose.
datastore/keycompat_test.go
Outdated
"testing" | ||
) | ||
|
||
var testCasesKeyCompat = []struct { |
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.
Not a big deal, but I usually prefer putting the test cases directly in the test where they're used. Then the slice can just be named tests
because it's clear what they're for.
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.
Done
t.Fatalf("%v", err.Error()) | ||
} | ||
if !reflect.DeepEqual(dk, tc.key) { | ||
t.Errorf("%s: got %+v, want %+v", tc.desc, dk, tc.key) |
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.
Please identify the function that failed. https://github.com/golang/go/wiki/CodeReviewComments#useful-test-failures
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.
Looks like tc.desc
is logged. What would make it clearer?
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.
I prefer both (function name + desc
), but OK with me to only do tc.desc
.
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.
Done
func protoToKey(p *cloudpb.Key) (*Key, error) { | ||
var key *Key | ||
var namespace string | ||
if partition := p.PartitionId; partition != nil { |
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.
Can you make that more clear? I wasn't sure where the copy/paste started & stopped.
datastore/keycompat.go
Outdated
// The context provided must be an App Engine context if running in first generation App Engine. | ||
// This can be called in the /_ah/start handler. It is safe to call multiple times, and is cheap to call, so can also be inserted as middleware. | ||
// | ||
// Enabling key compatibility not affect the encoding format used by Key.Encode, it only expands the type of keys that are able to be decoded with DecodeKey. |
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.
nit: grammar. Should be "does not affect"?
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.
Done
datastore/keycompat.go
Outdated
// | ||
// Enabling key compatibility not affect the encoding format used by Key.Encode, it only expands the type of keys that are able to be decoded with DecodeKey. | ||
func EnableKeyConversion(ctx context.Context) { | ||
if getKeyConversionAppID() == "" { |
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.
Am I misreading this? Won't getKeyConversionAppID()
always return "" until the code below this runs? And so this effectively prevents keyConversion.project
from ever getting set?
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.
Oops. Expression was inverted. PTAL. Good catch.
A Googler has manually verified that the CLAs look good. (Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.) ℹ️ Googlers: Go here for more info. |
A Googler has manually verified that the CLAs look good. (Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.) ℹ️ Googlers: Go here for more info. |
If a key can't be decoded, try to decode it with the encoding scheme from google.golang.org/appengine/datastore. Along with golang/appengine#192, this allows for cross-compatibility for encoded keys across the two libraries. Co-authored-by: Luke Mccoy <[email protected]> Co-authored-by: Chris Broadfoot <[email protected]> Change-Id: I7e091b37b184a12c30998c3c22baffb964018a61 Reviewed-on: https://code-review.googlesource.com/c/gocloud/+/41370 Reviewed-by: kokoro <[email protected]> Reviewed-by: Tyler Bui-Palsulich <[email protected]> Reviewed-by: Jean de Klerk <[email protected]> Reviewed-by: Steven Buss <[email protected]>
The main purpose of this change is to remove toil in migrating to the go111 runtime. This PR adds forward compatibility with cloud.google.com/go/datastore/key.Encode() so that customers can address migration to the go111 runtime in any order without concern for key encoding strings difference produced by the key.Encode() functions.