subStats.incrementFailedOps();
ServerStats.getInstance().incrementRequestsRedirect();
return;
}
final SubscribeRequest subRequest = request.getSubscribeRequest();
final ByteString subscriberId = subRequest.getSubscriberId();
MessageSeqId lastSeqIdPublished = MessageSeqId.newBuilder(seqId).setLocalComponent(seqId.getLocalComponent()).build();
final long requestTime = System.currentTimeMillis();
subMgr.serveSubscribeRequest(topic, subRequest, lastSeqIdPublished, new Callback<MessageSeqId>() {
@Override
public void operationFailed(Object ctx, PubSubException exception) {
channel.write(PubSubResponseUtils.getResponseForException(exception, request.getTxnId())).addListener(
ChannelFutureListener.CLOSE);
subStats.incrementFailedOps();
}
@Override
public void operationFinished(Object ctx, MessageSeqId resultOfOperation) {
TopicSubscriber topicSub = new TopicSubscriber(topic, subscriberId);
// race with channel getting disconnected while we are adding it
// to the 2 maps
synchronized (channel) {
if (!channel.isConnected()) {
// channel got disconnected while we were processing the
// subscribe request,
// nothing much we can do in this case
subStats.incrementFailedOps();
return;
}
if (null != sub2Channel.putIfAbsent(topicSub, channel)) {
// there was another channel mapped to this sub
PubSubException pse = new PubSubException.TopicBusyException(
"subscription for this topic, subscriberId is already being served on a different channel");
channel.write(PubSubResponseUtils.getResponseForException(pse, request.getTxnId()))
.addListener(ChannelFutureListener.CLOSE);
subStats.incrementFailedOps();
return;
} else {
// channel2sub is just a cache, so we can add to it
// without synchronization
channel2sub.put(channel, topicSub);
}
}
// First write success and then tell the delivery manager,
// otherwise the first message might go out before the response
// to the subscribe
channel.write(PubSubResponseUtils.getSuccessResponse(request.getTxnId()));
subStats.updateLatency(System.currentTimeMillis() - requestTime);
// want to start 1 ahead of the consume ptr
MessageSeqId seqIdToStartFrom = MessageSeqId.newBuilder(resultOfOperation).setLocalComponent(
resultOfOperation.getLocalComponent() + 1).build();
deliveryMgr.startServingSubscription(topic, subscriberId, seqIdToStartFrom,
new ChannelEndPoint(channel), TrueFilter.instance(), SubscriptionStateUtils
.isHubSubscriber(subRequest.getSubscriberId()));
}
}, null);
}