2018-10-29 17:19:37 +08:00
|
|
|
/*
|
2021-01-08 17:55:38 +01:00
|
|
|
* Copyright (C) 2009-2021 Lightbend Inc. <https://www.lightbend.com>
|
2013-04-16 22:31:09 +02:00
|
|
|
*/
|
|
|
|
|
|
2017-03-16 09:30:00 +01:00
|
|
|
package jdocs.io.japi;
|
2013-04-16 22:31:09 +02:00
|
|
|
|
|
|
|
|
import java.net.InetSocketAddress;
|
|
|
|
|
import java.util.LinkedList;
|
|
|
|
|
import java.util.Queue;
|
|
|
|
|
|
|
|
|
|
import akka.actor.ActorRef;
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
import akka.actor.AbstractActor;
|
2013-04-16 22:31:09 +02:00
|
|
|
import akka.event.Logging;
|
|
|
|
|
import akka.event.LoggingAdapter;
|
|
|
|
|
import akka.io.Tcp.CommandFailed;
|
|
|
|
|
import akka.io.Tcp.ConnectionClosed;
|
2013-05-26 10:58:55 +02:00
|
|
|
import akka.io.Tcp.Event;
|
2013-04-16 22:31:09 +02:00
|
|
|
import akka.io.Tcp.Received;
|
|
|
|
|
import akka.io.Tcp.Write;
|
|
|
|
|
import akka.io.Tcp.WritingResumed;
|
|
|
|
|
import akka.io.TcpMessage;
|
|
|
|
|
import akka.util.ByteString;
|
|
|
|
|
|
2021-05-07 22:27:39 +03:00
|
|
|
import static org.junit.Assert.assertEquals;
|
|
|
|
|
import static org.junit.Assert.assertFalse;
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #echo-handler
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
public class EchoHandler extends AbstractActor {
|
2013-04-16 22:31:09 +02:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), getSelf());
|
2013-04-16 22:31:09 +02:00
|
|
|
|
|
|
|
|
final ActorRef connection;
|
|
|
|
|
final InetSocketAddress remote;
|
|
|
|
|
|
|
|
|
|
public static final long MAX_STORED = 100000000;
|
|
|
|
|
public static final long HIGH_WATERMARK = MAX_STORED * 5 / 10;
|
|
|
|
|
public static final long LOW_WATERMARK = MAX_STORED * 2 / 10;
|
2019-01-12 04:00:53 +08:00
|
|
|
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
private long transferred;
|
|
|
|
|
private int storageOffset = 0;
|
|
|
|
|
private long stored = 0;
|
2021-05-07 22:27:39 +03:00
|
|
|
private Queue<ByteString> storage = new LinkedList<>();
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
|
|
|
|
|
private boolean suspended = false;
|
2019-01-12 04:00:53 +08:00
|
|
|
|
2013-05-26 10:58:55 +02:00
|
|
|
private static class Ack implements Event {
|
|
|
|
|
public final int ack;
|
2019-01-12 04:00:53 +08:00
|
|
|
|
2013-05-26 10:58:55 +02:00
|
|
|
public Ack(int ack) {
|
|
|
|
|
this.ack = ack;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-04-16 22:31:09 +02:00
|
|
|
|
|
|
|
|
public EchoHandler(ActorRef connection, InetSocketAddress remote) {
|
|
|
|
|
this.connection = connection;
|
|
|
|
|
this.remote = remote;
|
2019-01-12 04:00:53 +08:00
|
|
|
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
writing = writing();
|
2013-04-16 22:31:09 +02:00
|
|
|
|
|
|
|
|
// sign death pact: this actor stops when the connection is closed
|
|
|
|
|
getContext().watch(connection);
|
|
|
|
|
|
|
|
|
|
// start out in optimistic write-through mode
|
|
|
|
|
getContext().become(writing);
|
|
|
|
|
}
|
2019-01-12 04:00:53 +08:00
|
|
|
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
@Override
|
2019-01-12 04:00:53 +08:00
|
|
|
public Receive createReceive() {
|
|
|
|
|
return writing;
|
|
|
|
|
}
|
2013-04-16 22:31:09 +02:00
|
|
|
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
private final Receive writing;
|
2019-01-12 04:00:53 +08:00
|
|
|
|
|
|
|
|
private Receive writing() {
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
return receiveBuilder()
|
2019-01-12 04:00:53 +08:00
|
|
|
.match(
|
|
|
|
|
Received.class,
|
|
|
|
|
msg -> {
|
|
|
|
|
final ByteString data = msg.data();
|
|
|
|
|
connection.tell(TcpMessage.write(data, new Ack(currentOffset())), getSelf());
|
|
|
|
|
buffer(data);
|
|
|
|
|
})
|
|
|
|
|
.match(
|
|
|
|
|
Integer.class,
|
|
|
|
|
msg -> {
|
|
|
|
|
acknowledge(msg);
|
|
|
|
|
})
|
|
|
|
|
.match(
|
|
|
|
|
CommandFailed.class,
|
|
|
|
|
msg -> {
|
|
|
|
|
final Write w = (Write) msg.cmd();
|
|
|
|
|
connection.tell(TcpMessage.resumeWriting(), getSelf());
|
|
|
|
|
getContext().become(buffering((Ack) w.ack()));
|
|
|
|
|
})
|
|
|
|
|
.match(
|
|
|
|
|
ConnectionClosed.class,
|
|
|
|
|
msg -> {
|
|
|
|
|
if (msg.isPeerClosed()) {
|
|
|
|
|
if (storage.isEmpty()) {
|
|
|
|
|
getContext().stop(getSelf());
|
|
|
|
|
} else {
|
|
|
|
|
getContext().become(closing());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.build();
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
}
|
2013-04-16 22:31:09 +02:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #buffering
|
|
|
|
|
|
|
|
|
|
static final class BufferingState {
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
int toAck = 10;
|
|
|
|
|
boolean peerClosed = false;
|
|
|
|
|
}
|
2019-01-12 04:00:53 +08:00
|
|
|
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
protected Receive buffering(final Ack nack) {
|
|
|
|
|
final BufferingState state = new BufferingState();
|
2019-01-12 04:00:53 +08:00
|
|
|
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
return receiveBuilder()
|
2019-01-12 04:00:53 +08:00
|
|
|
.match(
|
|
|
|
|
Received.class,
|
|
|
|
|
msg -> {
|
|
|
|
|
buffer(msg.data());
|
|
|
|
|
})
|
|
|
|
|
.match(
|
|
|
|
|
WritingResumed.class,
|
|
|
|
|
msg -> {
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
writeFirst();
|
2019-01-12 04:00:53 +08:00
|
|
|
})
|
|
|
|
|
.match(
|
|
|
|
|
ConnectionClosed.class,
|
|
|
|
|
msg -> {
|
|
|
|
|
if (msg.isPeerClosed()) state.peerClosed = true;
|
|
|
|
|
else getContext().stop(getSelf());
|
|
|
|
|
})
|
|
|
|
|
.match(
|
|
|
|
|
Integer.class,
|
|
|
|
|
ack -> {
|
|
|
|
|
acknowledge(ack);
|
|
|
|
|
|
|
|
|
|
if (ack >= nack.ack) {
|
|
|
|
|
// otherwise it was the ack of the last successful write
|
|
|
|
|
|
|
|
|
|
if (storage.isEmpty()) {
|
|
|
|
|
if (state.peerClosed) getContext().stop(getSelf());
|
|
|
|
|
else getContext().become(writing);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
if (state.toAck > 0) {
|
|
|
|
|
// stay in ACK-based mode for a short while
|
|
|
|
|
writeFirst();
|
|
|
|
|
--state.toAck;
|
|
|
|
|
} else {
|
|
|
|
|
// then return to NACK-based again
|
|
|
|
|
writeAll();
|
|
|
|
|
if (state.peerClosed) getContext().become(closing());
|
|
|
|
|
else getContext().become(writing);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.build();
|
2013-04-16 22:31:09 +02:00
|
|
|
}
|
2019-01-12 04:00:53 +08:00
|
|
|
// #buffering
|
2013-04-16 22:31:09 +02:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #closing
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
protected Receive closing() {
|
|
|
|
|
return receiveBuilder()
|
2019-01-12 04:00:53 +08:00
|
|
|
.match(
|
|
|
|
|
CommandFailed.class,
|
|
|
|
|
msg -> {
|
|
|
|
|
// the command can only have been a Write
|
|
|
|
|
connection.tell(TcpMessage.resumeWriting(), getSelf());
|
|
|
|
|
getContext().become(closeResend(), false);
|
|
|
|
|
})
|
|
|
|
|
.match(
|
|
|
|
|
Integer.class,
|
|
|
|
|
msg -> {
|
|
|
|
|
acknowledge(msg);
|
|
|
|
|
if (storage.isEmpty()) getContext().stop(getSelf());
|
|
|
|
|
})
|
|
|
|
|
.build();
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
}
|
2013-04-16 22:31:09 +02:00
|
|
|
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
protected Receive closeResend() {
|
|
|
|
|
return receiveBuilder()
|
2019-01-12 04:00:53 +08:00
|
|
|
.match(
|
|
|
|
|
WritingResumed.class,
|
|
|
|
|
msg -> {
|
|
|
|
|
writeAll();
|
|
|
|
|
getContext().unbecome();
|
|
|
|
|
})
|
|
|
|
|
.match(
|
|
|
|
|
Integer.class,
|
|
|
|
|
msg -> {
|
|
|
|
|
acknowledge(msg);
|
|
|
|
|
})
|
|
|
|
|
.build();
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
}
|
2019-01-12 04:00:53 +08:00
|
|
|
// #closing
|
2013-04-16 22:31:09 +02:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #storage-omitted
|
2013-04-16 22:31:09 +02:00
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void postStop() {
|
|
|
|
|
log.info("transferred {} bytes from/to [{}]", transferred, remote);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #helpers
|
2013-04-16 22:31:09 +02:00
|
|
|
protected void buffer(ByteString data) {
|
|
|
|
|
storage.add(data);
|
|
|
|
|
stored += data.size();
|
|
|
|
|
|
|
|
|
|
if (stored > MAX_STORED) {
|
|
|
|
|
log.warning("drop connection to [{}] (buffer overrun)", remote);
|
2017-03-17 10:18:15 +01:00
|
|
|
getContext().stop(getSelf());
|
2013-04-16 22:31:09 +02:00
|
|
|
|
|
|
|
|
} else if (stored > HIGH_WATERMARK) {
|
|
|
|
|
log.debug("suspending reading at {}", currentOffset());
|
2017-03-16 09:30:00 +01:00
|
|
|
connection.tell(TcpMessage.suspendReading(), getSelf());
|
2013-04-16 22:31:09 +02:00
|
|
|
suspended = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void acknowledge(int ack) {
|
2021-05-07 22:27:39 +03:00
|
|
|
assertEquals(storageOffset, ack);
|
|
|
|
|
assertFalse(storage.isEmpty());
|
2013-04-16 22:31:09 +02:00
|
|
|
|
|
|
|
|
final ByteString acked = storage.remove();
|
|
|
|
|
stored -= acked.size();
|
|
|
|
|
transferred += acked.size();
|
|
|
|
|
storageOffset += 1;
|
|
|
|
|
|
|
|
|
|
if (suspended && stored < LOW_WATERMARK) {
|
|
|
|
|
log.debug("resuming reading");
|
2017-03-16 09:30:00 +01:00
|
|
|
connection.tell(TcpMessage.resumeReading(), getSelf());
|
2013-04-16 22:31:09 +02:00
|
|
|
suspended = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-01-12 04:00:53 +08:00
|
|
|
// #helpers
|
2013-04-16 22:31:09 +02:00
|
|
|
|
|
|
|
|
protected int currentOffset() {
|
|
|
|
|
return storageOffset + storage.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void writeAll() {
|
|
|
|
|
int i = 0;
|
|
|
|
|
for (ByteString data : storage) {
|
2017-03-16 09:30:00 +01:00
|
|
|
connection.tell(TcpMessage.write(data, new Ack(storageOffset + i++)), getSelf());
|
2013-04-16 22:31:09 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void writeFirst() {
|
2017-03-16 09:30:00 +01:00
|
|
|
connection.tell(TcpMessage.write(storage.peek(), new Ack(storageOffset)), getSelf());
|
2013-04-16 22:31:09 +02:00
|
|
|
}
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #storage-omitted
|
2013-04-16 22:31:09 +02:00
|
|
|
}
|
2019-01-12 04:00:53 +08:00
|
|
|
// #echo-handler
|