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

Nested selective receive fails when messages have the same object reference #212

Closed
voidstarstar opened this issue Jul 13, 2016 · 4 comments
Labels

Comments

@voidstarstar
Copy link
Contributor

This bug occurs when sending messages a and b to an actor such that a == b is true. This only appears to affect selective receive calls that are nested.

A very simple example to consistently reproduce the bug:

ActorRef<Integer> actorRef = new BasicActor<Integer, Integer>() {

    @Override
    protected Integer doRun() throws InterruptedException, SuspendExecution {
        Integer result = receive(a -> a + receive(b -> b));
        System.out.println(result);
        return null;
    }
}.spawn();

// Both messages share the same reference
actorRef.send(1);
actorRef.send(1);

Expected result: Print 2.

Actual result: It looks like one of the messages is silently dropped.

When changing the numbers to two different numbers, the bug goes away.

I suspect the bug might be caused by this section, but I am not really sure.

I think it's very important to allow the same message to be sent multiple times, especially since it is considered good practice to make messages immutable. I happened to run into this bug with my own custom message class, but any class that uses the flyweight pattern or interning for efficiency would also be affected (including enums, Integer, String, etc.).

Since this bug can occur due to a race condition, it is possible that this may also be the cause of other issues related to dropped messages.

@circlespainter
Copy link
Member

Why do you think it's a race condition? The actor mailbox is a single-consumer queue, i.e. it's only read by the actor strand; selective receives can be nested but the associated code should never be executed concurrently against a single mailbox. Also, it should only apply to selective receives.

The behavior you're seeing could also be related to this section but anyway I think the general cause is that at present the selective receive logic (especially the nested handling) relies on a notion of message identity (currently, primitive/reference equality).

@voidstarstar
Copy link
Contributor Author

Why do you think it's a race condition? The actor mailbox is a single-consumer queue, i.e. it's only read by the actor strand; selective receives can be nested but the associated code should never be executed concurrently against a single mailbox. Also, it should only apply to selective receives.

Sorry, I wasn't very clear in my last post. The consumer is single threaded as you described, but the producers are multithreaded. A race condition can determine the order in which producers add messages to the queue and this order is what determines if the bug appears or not.

For example:

Run 1:
Actor X sends Message 1
Actor X sends Message 2
Actor Y sends Message 1
Actor Y sends Message 2

Run 2:
Actor X sends Message 1
Actor Y sends Message 1
Actor X sends Message 2
Actor Y sends Message 2

Run 1 would not show the bug while run 2 would.

I just meant that the simple program in my previous post will consistently show the bug, but in more complex programs it is possible to have nondeterministic behavior due to the message ordering.

The behavior you're seeing could also be related to this section but anyway I think the general cause is that at present the selective receive logic (especially the nested handling) relies on a notion of message identity (currently, primitive/reference equality).

If fixed, I assume that the message position in the queue would be necessary since this is always unique while the message identity is not. Perhaps this could be achieved by inner receives using a view of the queue iterator that was filtered to not include the first instance of the message being processed by the outer receive.

@pron pron closed this as completed in 05aa43c Aug 4, 2016
@pron
Copy link
Contributor

pron commented Aug 4, 2016

@voidstarstar
Can you please try with 0.7.6-SNAPSHOT?

@voidstarstar
Copy link
Contributor Author

@pron
I can confirm that 0.7.6-SNAPSHOT appears to work perfectly! Thanks again for the great work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants