As you can see, the responses the client received are the same, hence they must have been executed sequentially,
and only the responses have arrived out of order. Thus, the responses obey the semantics of sequential operations
-- it is simply their arrival order is not
defined. You might find it easier for testing to use sequential identifiers for the operations, since that makes it
easier to follow the sequence of responses.
You might also note that out-of-order responses can only happen if the client does not wait for each individual answer
before continuing with sending operations.
While this loose ordering guarantee on responses might look strange at first, it will significantly simplify the
implementation of the binary tree and you are encouraged to make full use of it.
#### Your task
You can find code stubs in the file `BinaryTreeSet.scala` which provides you with the API as described above,
the `BinaryTreeSet` and `BinaryTreeNode` classes. The `BinaryTreeSet` represents the whole binary tree.
This is also the only actor that is explicitly created by the user and the only actor the user sends messages to.
You can implement as many or as few message handlers as you like and you can add additional variables or helper
functions. We provide suggestions in your code stub, marked with the comment `optional`, but you are free to use
it fully or partially; the optional elements are not part of the tested API.
To see a binary tree in operation check our provided tests in `BinaryTreeSuite.scala`. Note in particular
that it is the user who triggers garbage collection by sending a `GC` message (for the sake of simplicity of this exercise).
Don't forget to make sure that no `Operation` messages interfere during garbage collection and that the user does
not receive any messages that may result from the copying process. To achieve this, put any incoming operation message
into a queue during the garbage collection process. When the copying process is finished, re-send the queued messages
to the tree root and clear the queue.
The following may be useful for your implementation:
* Another way to stop an actor, besides the `stop` method you have seen, is to send it a `PoisonPill` message.
*`context.parent` returns the ActorRef of the actor which created the current actor (i.e. its parent).
* If you see a log message like the following
[INFO] [11/21/2013 14:04:13.237] [PostponeSpec-akka.actor.default-dispatcher-2] [akka://PostponeSpec/deadLetters] Message [actorbintree.BinaryTreeSet$OperationFinished] from Actor[akka://PostponeSpec/user/$e/my-actor#-1012560631] to Actor[akka://PostponeSpec/deadLetters] was not delivered. [1] dead letters encountered.
it means that one of your messages (here the OperationFinished) message was not delivered from actor `my-actor` to actor `deadLetters`—the latter is where actors forward their messages after they terminate.
You should check that you do not stop actors prematurely.
*A word on Actor counts:*
* The grader verifies that enough Actors are created when inserting elements.
* The grader also verifies that enough Actors are stopped in response to a `GC` command (i.e. for those elements that were previously marked removed from the set).