-
Notifications
You must be signed in to change notification settings - Fork 26
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
Fix #284 MPU Automatic Retry #286
Fix #284 MPU Automatic Retry #286
Conversation
…aded successfully
…ntaReflectionUtils" This reverts commit 1e5d633.
Closing this PR until it's actually ready for review. |
Reopening PR for visibility into ongoing work. |
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'm still trying to wrap my head around everything, so I'm afraid I'll need more than one pass.
- I know the changes are spread across a few different classes but somewhere there should be a Big Theory Statement with a few paragraphs of prose explaining how this fits together.
- Eventually we will need a CHANGELOG entry. It might be helpful to write that now, to explain how this interacts with NSS and what cases we are committing to work (and equally important, which will not work).
- What do we need to do either with tests here or on the CI side to make sure this continues to work in the future.
- Do any of the existing microbenchmarks cover an interaction that includes
record
? if so, is there a change? if not, some should be added to get a sense of how expensive an operation this is. - I believe some of the integration make strong assumptions about the handling of validated part numbers. Do they all still pass so far?
@@ -170,6 +170,20 @@ | |||
<version>${dependency.urlbuilder.version}</version> | |||
</dependency> | |||
|
|||
<!-- object cloning library for memoization of encryption state --> |
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 we include a "golden file" to deserialize as part of the kyro tests? That way we can be sure that version X objects can still be read if we bump the library dep to X+1.
Regarding shading/relocating. I think the stance that java-manta has taken so far is to do so wherever possible, so I would start with that as the default position.
@@ -170,6 +170,20 @@ | |||
<version>${dependency.urlbuilder.version}</version> | |||
</dependency> | |||
|
|||
<!-- object cloning library for memoization of encryption state --> | |||
<dependency> | |||
<groupId>uk.com.robust-it</groupId> |
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.
There are a few different deep cloneing libraries, any reason why this one in particular?
The readme says "Also cloning of files and streams might make the JVM crash." Are Files or Streams among the things we are cloning?
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 couldn't find any other libraries for deep-cloning besides this one and the copy functionality provided by kryo. Utilizing kryo would effectively mean bringing java-manta-client-kryo-serialization
into the main module.
I've limited usage of this library to only cloning Cipher
objects produced by the BouncyCastle library. The HmacCloner
and DigestCloner
classes in this PR leverage the Memoable
interface and some reflection to clone Hmac
objects instead.
@@ -89,7 +89,7 @@ public EncryptingPartEntity(final OutputStream cipherStream, | |||
|
|||
@Override | |||
public boolean isRepeatable() { | |||
return wrapped.isRepeatable(); | |||
return false; |
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.
What does isRepeatable
actually do? If we never "repeat" how is the retry and snapshot code triggered?
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.
The underlying Apache HTTP Client library uses this method to determine if it can automatically retry a request. MantaHttpRequestRetryHandler
is only responsible for determining whether a request should be retried based on the exception thrown. The HttpEntity
also gets to decide whether it is eligible for automatic retries by returning a value here. See HttpClient source for more context
Having this be true or delegate to the wrapped instance means that the underlying library could transparently retry the request. While it might be possible to automatically reset Cipher
state if the MantaHttpRequestRetryHandler
was used to coordinate the reset, we'd be adding a lot of complexity that we don't need right now. (This actually sounds like a possibility but enabling automatic retries to work in concert with encryption is not within the scope of this PR. Might tackle that later.)
Since uploadPart
already throws IOException
users know any call might fail and should be prepared to retry that part. Snapshots only exist in the scope of EncryptedMultipartManager#uploadPart
and act as a sort of momentarily-available checkpoint that should never be visible to the user.
* Object used to reset the state of encryption/authentication in case | ||
* a part needs to be reuploaded. | ||
*/ | ||
private static final EncryptionStateRecorder RECORDER = new EncryptionStateRecorder(); |
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.
Why static
?
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.
EncryptionStateRecorder
is a helper class and has no state of its own. This reference has been removed and the nature of the class has been clarified by newer commits (private constructor, only static methods)
} finally { | ||
if (encryptionState.getLastPartNumber() != partNumber && snapshot != null) { |
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.
Is the rewind done for any error during wrapped.uploadPart
? Previously the part ordering validation effectively kept consumers from shooting themselves in the foot with retrying parts. I'm trying to figure out of this opes up any new error paths.
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.
Using an inner try
now but yes I'm hesitant to classify exceptions by their likelihood of having affected Cipher
state an only rewind in certain cases, especially given the narrow scope of the inner try
block. It seems much more straightforward to always reset encryption state if we don't make it to the setLastPartNumber
invocation.
} finally { | ||
if (encryptionState.getLastPartNumber() != partNumber && snapshot != null) { | ||
// a snapshot was prepared but we didn't make it past uploadPart, rewind EncryptionState | ||
RECORDER.rewind(encryptionState, snapshot); |
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 this possibly throw an exception? I'm worried about anything happening in the same finally
as the lock release.
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.
Moved into an inner try
block to address this.
try { | ||
writeField(FIELD_HMACOUTPUTSTREAM_HMAC, digestStream, snapshot.getHmac()); | ||
} catch (IllegalAccessException e) { | ||
throw new MantaReflectionException("Failed to overwrite HmacOutputStream's hmac", e); |
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.
Is there any additional context or IDs from EncryptionState that we can add to this and the following exceptions?
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.
Changed rewind
to accept the EncryptedMultipartUpload
object instead to it can include the ID in addition to the part number in the exception messages.
|
||
private void failAfterMinimum(final int next) throws SpuriousIOException { | ||
if (count.get() + next > minimumBytes) { | ||
throw new SpuriousIOException("Random 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.
nit: This is and arbitrary but not "random" error. It might be nice to include which byte the error was induced at in the message.
ProblemThe current design of MPU operations involves creating a new
ProposalWe can remedy this situation by taking snapshots of
LimitationsUnfortunately the implementation of By cloning only the |
Answering general questions from @cburroughs
|
3ebe286
to
ffbfe2c
Compare
ffbfe2c
to
1e35c3c
Compare
…ach combination of cipher mode and strength
@cburroughs @dekobon Ready for a second round of reviews. I would specifically appreciate review of the way the objenisis and cloning libraries are shaded. |
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.
LGTM
HmacSHA512 | ||
} | ||
|
||
/** |
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 isn't a package default constructor. This is a private constructor.
@@ -0,0 +1,176 @@ | |||
/* | |||
* Copyright (c) 2016-2017, Joyent, Inc. All rights reserved. |
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.
Change copyright to 2017.
For #284:
RenameReflectionUtils
toMantaReflectionUtils
and move fromjava-manta-client-kryo serialization
module tojava-manta-client
moduleEncryptedMultipartManager
incrementlastPartNumber
only if the part was uploaded successfullyHMacCloner
and testsCipherCloner
and testsEncryptionStateRecorder
EncryptedMultipartManager
useEncryptionStateCloner
to checkpoint encryption state between partsEncryptedServerSideMultipartManagerIT#canRetryUploadPart
passestest everything with and withoutdetermined that memoization of PKCS11 Cipher state is not feasible, all MPU operations must use BouncyCastlelibnss
enabledEncryptedServerSideMultipartManagerIT#canRetryUploadPart
to include retry for multiple parts, including the first partHmacCloner
works with-Dcom.twmacinta.util.MD5.NATIVE_LIB_FILE=