Uh oh!
There was an error while loading. Please reload this page.
API, Core: Introduce a generic abstraction to replace ManifestListFile - #17545
API, Core: Introduce a generic abstraction to replace ManifestListFile#17545gaborkaszab wants to merge 4 commits into
Conversation
| * @deprecated will be removed in 2.0.0; use {@link #newInputFile(EncryptableFile)} instead. | ||
| */ | ||
| @Deprecated | ||
| default InputFile newInputFile(ManifestListFile manifestList) { |
There was a problem hiding this comment.
I dropped BaseManifestListFile because that was package private. Now, there is no implementation in the library that can call this function, still I don't think we can drop this, because it'd break API for users that happen to implement their own ManifestListFile. Not likely, but technically feasible.
| * A file that may be encrypted. If it is encrypted, its encrypted key metadata is tracked in the | ||
| * table metadata encryption keys and is referenced by a key ID. | ||
| */ | ||
| public interface EncryptableFile { |
There was a problem hiding this comment.
Naming: "Encryptable" describes a capability every file has, not the specific concept/state represented here. I would suggest EncryptedFile and let the Javadoc cover the "may or may not carry a keyId" case.
There was a problem hiding this comment.
Changed to EncryptedFile, however, I'm still not comfortable with the vile name. The name suggests the file is encrypted, but it's may or may not. Maybe FileWithEncryptedKey ?
There was a problem hiding this comment.
let's see if others have a better name than EncryptedFile.
We do have PlaintextEncryptionManager for no encryption too.
There was a problem hiding this comment.
I feel FileWithEncryptedKey is more accurate.
There was a problem hiding this comment.
Renamed the interface to FileWithEncryptedKey
| * The file key metadata can be encrypted. Returns ID of encryption key or null if it's not | ||
| * encrypted. | ||
| */ | ||
| String encryptionKeyID(); |
There was a problem hiding this comment.
encryptionKeyID()→keyId()for consistency withSnapshot.keyId()andEncryptedKey.keyId()(IDcaps is out of style — even the local variables inEncryptionUtilaremanifestListKeyId).- Javadoc suggestion:
/** Returns the encryption key ID for this file, or null if the file is not encrypted. */— the interface-level javadoc already covers the mapping toTableMetadata.encryptionKeys(), so the method sentence can stay short.
There was a problem hiding this comment.
Thanks for the comment suggestion! Applied.
About the function name: I'm not sure we can change the function name, because that would break the API for ManifestListFile that is derived from this interface.
Alternatively, we can avoid deriving ManifestListFile from the new interface, but then we won't be able to cast it to the new interface and delegate to the new function signature like in FileIO or in EncryptionUtil:newInputFile((EncryptableFile) manifestList)
There was a problem hiding this comment.
if we want to, we can still rename it to a new method in the EncryptedFile interface and keep the old method in ManifestListFile with a default impl that just forwards.
but I am also ok to keep the old name
There was a problem hiding this comment.
Could there technically be custom implementations of ManifestListFile out there overriding encryptionKeyID to not delegate to the new function, that would break the design here, because internally we would only call the new version of the function?
I think it's cleaner to keep the same API that we had before.
There was a problem hiding this comment.
I went through this again, and I think I managed to come up with a solution that isn't a breaking change for custom implementations of ManifestListFile. See EncryptionUtil.decryptKeyMetadata functions where I introduced a variation that accepts the key ID from the various versions.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
0a3b903 to
c08b3fdCompare
gaborkaszab
left a comment
There was a problem hiding this comment.
Thanks for taking a look, @stevenzwu !
| * A file that may be encrypted. If it is encrypted, its encrypted key metadata is tracked in the | ||
| * table metadata encryption keys and is referenced by a key ID. | ||
| */ | ||
| public interface EncryptableFile { |
There was a problem hiding this comment.
Changed to EncryptedFile, however, I'm still not comfortable with the vile name. The name suggests the file is encrypted, but it's may or may not. Maybe FileWithEncryptedKey ?
| * The file key metadata can be encrypted. Returns ID of encryption key or null if it's not | ||
| * encrypted. | ||
| */ | ||
| String encryptionKeyID(); |
There was a problem hiding this comment.
Thanks for the comment suggestion! Applied.
About the function name: I'm not sure we can change the function name, because that would break the API for ManifestListFile that is derived from this interface.
Alternatively, we can avoid deriving ManifestListFile from the new interface, but then we won't be able to cast it to the new interface and delegate to the new function signature like in FileIO or in EncryptionUtil:newInputFile((EncryptableFile) manifestList)
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
varun-lakhyani
left a comment
There was a problem hiding this comment.
Overall LGTM.
- Data types / return types are consistently migrated to EncryptedFile.
- Deprecation javadocs are clear
- ManifestListFile's own deprecation javadoc + extends EncryptedFile explains most of the seemingly-confusing type/return changes across the PR (e.g. toManifestListFile() returning EncryptedFile).
Uh oh!
There was an error while loading. Please reload this page.
| * @param manifestList a ManifestListFile | ||
| * @param em the table's EncryptionManager | ||
| * @return a decrypted key metadata buffer | ||
| * @deprecated since 1.12.0. Will be removed in 1.13.0; use {@link |
There was a problem hiding this comment.
Shouldn't the removal version be the next major version (2.0.0) as you have done in the other deprecation tag in this PR?
There was a problem hiding this comment.
In core/ we can remove stuff in the next minor release, while in api/ it's stricter, the next major is the closest one for removal.
There was a problem hiding this comment.
Giving this a second thought I think you're right. As long as we keep the ManifestListFile interface (until 2.0.0 as it's in api/) we have to keep the encryption/decryption methods for that class. Otherwise it might be a behavior change for custom implementation if we silently fall back to the method for EncryptedFile.
| String encryptionKeyID(); | ||
| /** Decrypt and return the file key metadata */ | ||
| ByteBuffer decryptKeyMetadata(EncryptionManager em); |
There was a problem hiding this comment.
Carry over from existing design, but this method feels like it belongs on the encryption service rather than on the file value type. The file only supplies the key ID. I don't think it can simply be dropped, though: the caller (EncryptingFileIO) is in api and EncryptionUtil is in core, so api can't call it directly.
If we want it off EncryptedFile, the clean version is to move the operation onto EncryptionManager (impl already in core, and EncryptingFileIO already holds one), keyed by encryptionKeyID().
It's fine if we want to do in a followup.
cc @rdblue in case he has any thoughts.
There was a problem hiding this comment.
Hmm, with this the only purpose of putting this functionality into EncryptionManager is that its implementation in core/ can delegate to EncryptionUtil to get around the issue that EncryptingFileIO.newInputFile() is in api/ and can't call the util method in core/. I'm not entirely comfortable with that design, while I'm not comfortable with the current one either. At least we keep existing api with the current one.
There was a problem hiding this comment.
I likes Anoop suggestion here of dropping this method and let callers use the EncryptionUtil.decryptXXX directly. Since we are defining a new interface, it seems like a good opportunity to deprecate. Then this class becomes just a POJO envelope interface.
There was a problem hiding this comment.
I gave this a try and in the latest version of this PR you can see how this can be implemented. I dropped the decryptKeyMetadata method from the new interface. However, to be able to use the underlying EncryptionUtil.decryptKeyMetadata() that is in core/, from EncryptingFileIO that is in api/, I had to introduce the same in EncryptionManager. Basically, this is inline with @anoopj 's suggestion. Let me know what you think!
gaborkaszab
left a comment
There was a problem hiding this comment.
Thanks for looking into this @stevenzwu@huaxingao@anoopj !
I renamed the new interface, also went for the simpler method keyId() while keeping compatibility with custom ManifestListFile implementations.
| * @param manifestList a ManifestListFile | ||
| * @param em the table's EncryptionManager | ||
| * @return a decrypted key metadata buffer | ||
| * @deprecated since 1.12.0. Will be removed in 1.13.0; use {@link |
There was a problem hiding this comment.
Giving this a second thought I think you're right. As long as we keep the ManifestListFile interface (until 2.0.0 as it's in api/) we have to keep the encryption/decryption methods for that class. Otherwise it might be a behavior change for custom implementation if we silently fall back to the method for EncryptedFile.
| * The file key metadata can be encrypted. Returns ID of encryption key or null if it's not | ||
| * encrypted. | ||
| */ | ||
| String encryptionKeyID(); |
There was a problem hiding this comment.
I went through this again, and I think I managed to come up with a solution that isn't a breaking change for custom implementations of ManifestListFile. See EncryptionUtil.decryptKeyMetadata functions where I introduced a variation that accepts the key ID from the various versions.
| String encryptionKeyID(); | ||
| /** Decrypt and return the file key metadata */ | ||
| ByteBuffer decryptKeyMetadata(EncryptionManager em); |
There was a problem hiding this comment.
Hmm, with this the only purpose of putting this functionality into EncryptionManager is that its implementation in core/ can delegate to EncryptionUtil to get around the issue that EncryptingFileIO.newInputFile() is in api/ and can't call the util method in core/. I'm not entirely comfortable with that design, while I'm not comfortable with the current one either. At least we keep existing api with the current one.
Uh oh!
There was an error while loading. Please reload this page.
| * A file that may be encrypted. If it is encrypted, its encrypted key metadata is tracked in the | ||
| * table metadata encryption keys and is referenced by a key ID. | ||
| */ | ||
| public interface EncryptableFile { |
There was a problem hiding this comment.
Renamed the interface to FileWithEncryptedKey
…ManifestListFile ManifestListFile and its implementation contains nothing that is specific to manifest lists. It is more generally related to files that use TableMetadata.encryptionKeys to store encrypted encryption key metadata that are referred to by a key ID. This PR introduces a more general interface that can be used accross multiple file types like manifest lists, V4 root manifests, table statistics and partition statistics. The less general functionality specific to manifest lists is deprecated or removed where possible.
5ee1f33 to
1000d01Compare1000d01 to
d3dec6dCompare| * A file that may be encrypted. If it is encrypted, its encrypted key metadata is tracked in the | ||
| * table metadata encryption keys and is referenced by a key ID. | ||
| */ | ||
| public interface FileWithEncryptedKey { |
There was a problem hiding this comment.
I know we have gone through a couple of iterations on naming (EncryptableFile, EncryptedFile), which is a bit tricky in this case.
Just throwing out a couple more for considerations: FileWithKeyId or FileWithEncryptionKeyId?
There was a problem hiding this comment.
I like FileWithKeyId, renamed the new interface to that. Thanks for the suggestion @stevenzwu !
Also, one minor correction to ManifestListFile: We can't default encryptionKeyId() to return keyId, because custom implementations might not implement keyId(), hence would be broken.
ManifestListFile and its implementation contains nothing that is specific to manifest lists. It is more generally related to files that use TableMetadata.encryptionKeys to store encrypted encryption key metadata that are referred to by a key ID.
This PR introduces a more general interface that can be used accross multiple file types like manifest lists, V4 root manifests, table statistics and partition statistics. The less general functionality specific to manifest lists is deprecated or removed where possible.