Skip to content

Commit 6df6c45

Browse files
first impl. busy wait holds thread so onNext is not called
Signed-off-by: Matt Peterson <[email protected]>
1 parent 8e98b5b commit 6df6c45

File tree

14 files changed

+187
-438
lines changed

14 files changed

+187
-438
lines changed

server/src/main/java/com/hedera/block/server/BlockStreamService.java

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import com.hedera.block.protos.BlockStreamServiceGrpcProto;
2121
import com.hedera.block.server.consumer.LiveStreamObserver;
2222
import com.hedera.block.server.consumer.LiveStreamObserverImpl;
23-
import com.hedera.block.server.mediator.StreamMediator;
23+
import com.hedera.block.server.persistence.BlockPersistenceHandler;
2424
import com.hedera.block.server.producer.ProducerBlockStreamObserver;
2525
import io.grpc.stub.StreamObserver;
2626
import io.helidon.webserver.grpc.GrpcService;
@@ -42,19 +42,18 @@ public class BlockStreamService implements GrpcService {
4242
private final System.Logger LOGGER = System.getLogger(getClass().getName());
4343

4444
private final long timeoutThresholdMillis;
45-
private final StreamMediator<BlockStreamServiceGrpcProto.Block, BlockStreamServiceGrpcProto.BlockResponse> streamMediator;
45+
private final BlockPersistenceHandler<BlockStreamServiceGrpcProto.Block> blockPersistenceHandler;
4646

4747
/**
4848
* Constructor for the BlockStreamService class.
4949
*
5050
* @param timeoutThresholdMillis the timeout threshold in milliseconds
51-
* @param streamMediator the stream mediator
5251
*/
5352
public BlockStreamService(final long timeoutThresholdMillis,
54-
final StreamMediator<BlockStreamServiceGrpcProto.Block, BlockStreamServiceGrpcProto.BlockResponse> streamMediator) {
53+
final BlockPersistenceHandler<BlockStreamServiceGrpcProto.Block> blockPersistenceHandler) {
5554

5655
this.timeoutThresholdMillis = timeoutThresholdMillis;
57-
this.streamMediator = streamMediator;
56+
this.blockPersistenceHandler = blockPersistenceHandler;
5857
}
5958

6059
/**
@@ -101,7 +100,7 @@ private StreamObserver<BlockStreamServiceGrpcProto.Block> streamSink(
101100
final StreamObserver<BlockStreamServiceGrpcProto.BlockResponse> responseStreamObserver) {
102101
LOGGER.log(System.Logger.Level.DEBUG, "Executing bidirectional streamSink method");
103102

104-
return new ProducerBlockStreamObserver(streamMediator, responseStreamObserver);
103+
return new ProducerBlockStreamObserver(blockPersistenceHandler, responseStreamObserver);
105104
}
106105

107106
/**
@@ -117,17 +116,14 @@ private StreamObserver<BlockStreamServiceGrpcProto.BlockResponse> streamSource(f
117116
LOGGER.log(System.Logger.Level.DEBUG, "Executing bidirectional streamSource method");
118117

119118
// Return a custom StreamObserver to handle streaming blocks from the producer.
120-
final LiveStreamObserver<BlockStreamServiceGrpcProto.Block, BlockStreamServiceGrpcProto.BlockResponse> streamObserver = new LiveStreamObserverImpl(
119+
LiveStreamObserver<BlockStreamServiceGrpcProto.BlockResponse> liveStreamObserver = new LiveStreamObserverImpl(
121120
timeoutThresholdMillis,
122121
Clock.systemDefaultZone(),
123-
Clock.systemDefaultZone(),
124-
streamMediator,
122+
blockPersistenceHandler,
125123
responseStreamObserver);
126124

127-
// Subscribe the observer to the mediator
128-
streamMediator.subscribe(streamObserver);
129-
130-
return streamObserver;
125+
liveStreamObserver.emitBlocks();
126+
return liveStreamObserver;
131127
}
132128
}
133129

server/src/main/java/com/hedera/block/server/Server.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package com.hedera.block.server;
1818

1919
import com.hedera.block.protos.BlockStreamServiceGrpcProto;
20-
import com.hedera.block.server.mediator.LiveStreamMediatorImpl;
2120
import com.hedera.block.server.persistence.WriteThroughCacheHandler;
2221
import com.hedera.block.server.persistence.storage.BlockStorage;
2322
import com.hedera.block.server.persistence.storage.FileSystemBlockStorage;
@@ -64,7 +63,7 @@ public static void main(final String[] args) {
6463

6564
// TODO: Make timeoutThresholdMillis configurable
6665
final BlockStreamService blockStreamService = new BlockStreamService(1500,
67-
new LiveStreamMediatorImpl(new WriteThroughCacheHandler(blockStorage)));
66+
new WriteThroughCacheHandler(blockStorage));
6867

6968
// Start the web server
7069
WebServer.builder()

server/src/main/java/com/hedera/block/server/consumer/LiveStreamObserver.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,11 @@
2424
* the implementation of this interface can receive and process inbound messages with different types from
2525
* the producer and response messages from the consumer.
2626
*
27-
* @param <U> the type of the block
2827
* @param <V> the type of the StreamObserver
2928
*/
30-
public interface LiveStreamObserver<U, V> extends StreamObserver<V> {
29+
public interface LiveStreamObserver<V> extends StreamObserver<V> {
3130

3231
/**
33-
* Pass the block to the observer.
34-
*
35-
* @param block - the block to be passed to the observer
3632
*/
37-
void notify(final U block);
33+
void emitBlocks();
3834
}

server/src/main/java/com/hedera/block/server/consumer/LiveStreamObserverImpl.java

Lines changed: 38 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -17,73 +17,46 @@
1717
package com.hedera.block.server.consumer;
1818

1919
import com.hedera.block.protos.BlockStreamServiceGrpcProto;
20-
import com.hedera.block.server.mediator.StreamMediator;
20+
import com.hedera.block.server.persistence.BlockPersistenceHandler;
2121
import io.grpc.stub.StreamObserver;
2222

2323
import java.time.Clock;
2424
import java.time.InstantSource;
25+
import java.util.concurrent.atomic.AtomicLong;
2526

2627
/**
2728
* The LiveStreamObserverImpl class implements the LiveStreamObserver interface to pass blocks to the downstream consumer
2829
* via the notify method and manage the bidirectional stream to the consumer via the onNext, onError, and onCompleted methods.
2930
*/
30-
public class LiveStreamObserverImpl implements LiveStreamObserver<BlockStreamServiceGrpcProto.Block, BlockStreamServiceGrpcProto.BlockResponse> {
31+
public class LiveStreamObserverImpl implements LiveStreamObserver<BlockStreamServiceGrpcProto.BlockResponse> {
3132

3233
private final System.Logger LOGGER = System.getLogger(getClass().getName());
3334

34-
private final StreamMediator<BlockStreamServiceGrpcProto.Block, BlockStreamServiceGrpcProto.BlockResponse> mediator;
35+
private final BlockPersistenceHandler<BlockStreamServiceGrpcProto.Block> blockPersistenceHandler;
3536
private final StreamObserver<BlockStreamServiceGrpcProto.Block> responseStreamObserver;
3637

3738
private final long timeoutThresholdMillis;
38-
39-
private final InstantSource producerLivenessClock;
40-
private long producerLivenessMillis;
41-
42-
private final InstantSource consumerLivenessClock;
43-
private long consumerLivenessMillis;
39+
private final AtomicLong consumerLivenessMillis;
40+
private final AtomicLong counter;
4441

4542
/**
4643
* Constructor for the LiveStreamObserverImpl class.
4744
*
48-
* @param mediator the mediator
4945
* @param responseStreamObserver the response stream observer
5046
*/
5147
public LiveStreamObserverImpl(
5248
final long timeoutThresholdMillis,
53-
final InstantSource producerLivenessClock,
5449
final InstantSource consumerLivenessClock,
55-
final StreamMediator<BlockStreamServiceGrpcProto.Block, BlockStreamServiceGrpcProto.BlockResponse> mediator,
50+
final BlockPersistenceHandler<BlockStreamServiceGrpcProto.Block> blockPersistenceHandler,
5651
final StreamObserver<BlockStreamServiceGrpcProto.Block> responseStreamObserver) {
5752

5853
this.timeoutThresholdMillis = timeoutThresholdMillis;
59-
this.producerLivenessClock = producerLivenessClock;
60-
this.consumerLivenessClock = consumerLivenessClock;
61-
this.mediator = mediator;
54+
this.blockPersistenceHandler = blockPersistenceHandler;
6255
this.responseStreamObserver = responseStreamObserver;
6356

64-
this.producerLivenessMillis = producerLivenessClock.millis();
65-
this.consumerLivenessMillis = consumerLivenessClock.millis();
66-
}
67-
68-
/**
69-
* Pass the block to the observer provided by Helidon
70-
*
71-
* @param block the block to be passed to the observer
72-
*/
73-
@Override
74-
public void notify(final BlockStreamServiceGrpcProto.Block block) {
75-
76-
// Check if the consumer has timed out. If so, unsubscribe the observer from the mediator.
77-
if (consumerLivenessClock.millis() - consumerLivenessMillis > timeoutThresholdMillis) {
78-
if (mediator.isSubscribed(this)) {
79-
LOGGER.log(System.Logger.Level.DEBUG, "Consumer timeout threshold exceeded. Unsubscribing observer.");
80-
mediator.unsubscribe(this);
81-
}
82-
} else {
83-
// Refresh the producer liveness and pass the block to the observer.
84-
producerLivenessMillis = producerLivenessClock.millis();
85-
responseStreamObserver.onNext(block);
86-
}
57+
this.consumerLivenessMillis = new AtomicLong(consumerLivenessClock.millis());
58+
// this.counter = new AtomicLong(blockPersistenceHandler.getLastBlockId());
59+
this.counter = new AtomicLong(1);
8760
}
8861

8962
/**
@@ -94,12 +67,21 @@ public void notify(final BlockStreamServiceGrpcProto.Block block) {
9467
@Override
9568
public void onNext(final BlockStreamServiceGrpcProto.BlockResponse blockResponse) {
9669

97-
if (producerLivenessClock.millis() - producerLivenessMillis > timeoutThresholdMillis) {
98-
LOGGER.log(System.Logger.Level.DEBUG, "Producer timeout threshold exceeded. Unsubscribing observer.");
99-
mediator.unsubscribe(this);
100-
} else {
101-
LOGGER.log(System.Logger.Level.DEBUG, "Received response block " + blockResponse);
102-
consumerLivenessMillis = consumerLivenessClock.millis();
70+
// update the consumer liveness clock
71+
consumerLivenessMillis.set(Clock.systemDefaultZone().millis());
72+
73+
if (!isThresholdExceeded()) {
74+
emitBlocks();
75+
}
76+
}
77+
78+
@Override
79+
public void emitBlocks() {
80+
final long latestBlockId = counter.get();
81+
for (BlockStreamServiceGrpcProto.Block block : blockPersistenceHandler.readRange(latestBlockId, latestBlockId + 1)) {
82+
LOGGER.log(System.Logger.Level.INFO, "Thread: {0}-{1}, Emitting block: {2}", Thread.currentThread().threadId(), Thread.currentThread().getName(), block.getId());
83+
responseStreamObserver.onNext(block);
84+
counter.incrementAndGet();
10385
}
10486
}
10587

@@ -112,7 +94,6 @@ public void onNext(final BlockStreamServiceGrpcProto.BlockResponse blockResponse
11294
@Override
11395
public void onError(final Throwable t) {
11496
LOGGER.log(System.Logger.Level.ERROR, "Unexpected consumer stream communication failure: %s".formatted(t), t);
115-
mediator.unsubscribe(this);
11697
}
11798

11899
/**
@@ -121,8 +102,17 @@ public void onError(final Throwable t) {
121102
*/
122103
@Override
123104
public void onCompleted() {
124-
LOGGER.log(System.Logger.Level.DEBUG, "gRPC connection completed. Unsubscribing observer.");
125-
mediator.unsubscribe(this);
126-
LOGGER.log(System.Logger.Level.DEBUG, "Unsubscribed observer.");
105+
LOGGER.log(System.Logger.Level.INFO, "gRPC connection completed.");
106+
}
107+
108+
private boolean isThresholdExceeded() {
109+
final long currentTimeMillis = Clock.systemDefaultZone().millis();
110+
final long elapsedMillis = currentTimeMillis - consumerLivenessMillis.get();
111+
if (elapsedMillis> timeoutThresholdMillis) {
112+
LOGGER.log(System.Logger.Level.INFO, "Elapsed milliseconds: " + elapsedMillis + ", timeout threshold: " + timeoutThresholdMillis);
113+
return true;
114+
}
115+
116+
return false;
127117
}
128118
}

server/src/main/java/com/hedera/block/server/mediator/LiveStreamMediatorImpl.java

Lines changed: 0 additions & 99 deletions
This file was deleted.

0 commit comments

Comments
 (0)