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

Handle exceptions and thread interrupts during DocumentContext lock #390

Closed
JerryShea opened this issue Oct 24, 2017 · 14 comments
Closed

Handle exceptions and thread interrupts during DocumentContext lock #390

JerryShea opened this issue Oct 24, 2017 · 14 comments
Assignees

Comments

@JerryShea
Copy link
Contributor

JerryShea commented Oct 24, 2017

The below code implements a typical pattern to write to a chronicle i.e. get the writing DocumentContext in a try-with-resources and close it when finished writing.

public class BinaryMethodWriterInvocationHandler ...
    ...
    @Override
    protected void handleInvoke(Method method, Object[] args) {
        try (@NotNull DocumentContext context = appender.writingDocument()) {
            Wire wire = context.wire();
            handleInvoke(method, args, wire);
            wire.padToCacheAlign();
        }
    }

If our thread is interrupted during the serialisation (which in this case happens during handleInvoke) then a java.nio.channels.ClosedByInterruptException is thrown during the close of the context. As the close seems to perform most of its function still, it appears to the chronicle (and any readers) that a valid object has been written although the object is only partially written.

See net.openhft.chronicle.queue.impl.single.NotCompleteTest#testInterruptedDuringSerialisation

@peter-lawrey
Copy link
Member

peter-lawrey commented Oct 24, 2017 via email

@JerryShea
Copy link
Contributor Author

JerryShea commented Oct 24, 2017

Yes - agree. Although with try-with-resources the catch is run after the resource is closed. I think we need something like

        @NotNull DocumentContext context = appender.writingDocument();
        try {
            Wire wire = context.wire();
            handleInvoke(method, args, wire);
            wire.padToCacheAlign();
        } catch (Throwable t) {
            context.setRollback();
        } finally {
            context.close();
        }

which unfortunately is not as concise

@JerryShea JerryShea reopened this Oct 24, 2017
@peter-lawrey
Copy link
Member

peter-lawrey commented Oct 24, 2017 via email

@RobAustin
Copy link
Member

@JerryShea I'm keen not to have a list of git issue that we never address, can you work on this or close is as a point of discussion.

@JerryShea
Copy link
Contributor Author

JerryShea commented Dec 4, 2017

@RobAustin, there is still a problem when we detect this situation and recover from it, but only with lazy indexing. I have a test for it, just not a fix yet. Will work on this week. Now fixed with commit fa47af7
@peter-lawrey, agree with you about the higher level interface. Instead of the current pattern

        try (@NotNull DocumentContext context = appender.writingDocument()) {
           //  do something with context;
        }

I suppose we should support an API something like this

appender.writingDocument().writeWithContext(context -> {
           //  do something with context;
});

Any comments?

@peter-lawrey
Copy link
Member

peter-lawrey commented Dec 4, 2017 via email

@JerryShea
Copy link
Contributor Author

So, BinaryMethodWriterInvocationHandler could look something like this:

appender.writingDocument().writeWithContext(context -> {
    Wire wire = context.wire();
    handleInvoke(method, args, wire);
    wire.padToCacheAlign();
});

But the lambda may well have to moved in to a field as it captures this.handleInvoke in the above example.
The writeWithContext method would do the following:

void writeWithContext(Consumer<DocumentContext> toRun) {
    try {
        toRun.apply(context);
    } catch (Throwable t) {
        context.setRollback();
        Jvm.rethrow(t);
    } finally {
        context.close();
    }
}

And so any exception that occurred during writing would mean that the context would rollback the write. Some exceptions may mean that it is not possible to rollback the write (e.g. if we can no longer write to the chronicle) and so in this case, timedStoreRecovery will have to kick in next time it read from or written to.

@peter-lawrey
Copy link
Member

peter-lawrey commented Dec 5, 2017 via email

@peter-lawrey
Copy link
Member

peter-lawrey commented Dec 5, 2017 via email

JerryShea added a commit that referenced this issue Dec 6, 2017
JerryShea added a commit that referenced this issue Dec 6, 2017
JerryShea added a commit that referenced this issue Dec 7, 2017
…n during writing, so as to tell the DocumentContext to not commit the message #390
@JerryShea
Copy link
Contributor Author

JerryShea commented Dec 7, 2017

So we have 3 options:

  1. higher level interface so the user doesn't have to worry about try/catch/finally. This is a bit of effort and a bit of change to the API
  2. add a setRollback method to DocumentContext so the user can use the try/catch/finally pattern
  3. add an option to context where a success (commit?) method must be called otherwise rollback

The easiest and lowest risk of these is 2. so I have implemented that with OpenHFT/Chronicle-Wire@0ffaeb1

@RobAustin
Copy link
Member

RobAustin commented Dec 7, 2017 via email

@peter-lawrey
Copy link
Member

peter-lawrey commented Dec 7, 2017 via email

JerryShea added a commit to OpenHFT/Chronicle-Wire that referenced this issue Dec 14, 2017
@JerryShea
Copy link
Contributor Author

@peter-lawrey - yes - see OpenHFT/Chronicle-Wire@6ece62b

JerryShea added a commit that referenced this issue Dec 17, 2017
…dWriter when exception takes place during write (DocumentContext gets rolled back) #390
@JerryShea
Copy link
Contributor Author

Have documented this behaviour in a test and added doco.

@JerryShea JerryShea changed the title Possible to write a partially serialised object Handle exceptions and thread interrupts during DocumentContext lock Dec 18, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants