-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Simulator: BlockStreamManager impl for very large DataSets (#225)
Signed-off-by: Alfredo Gutierrez <[email protected]>
- Loading branch information
1 parent
90e556a
commit a3a97cc
Showing
21 changed files
with
465 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# Block Stream Simulator | ||
|
||
## Overview | ||
|
||
The Block Stream Simulator is designed to simulate block streaming for Hedera Hashgraph. | ||
It uses various configuration sources and dependency injection to manage its components. | ||
|
||
## Prerequisites | ||
|
||
- Java 21 | ||
- Gradle | ||
- IntelliJ IDEA (recommended for development) | ||
|
||
## Project Design Structure | ||
|
||
Uses Dagger2 for dependency injection, the project has a modular structure and divides the Dagger dependencies into modules, but all modules used can be found at the root Injection Module: | ||
```plaintext | ||
src/java/com/hedera/block/simulator/BlockStreamSimulatorInjectionModule.java | ||
``` | ||
Entry point for the project is `BlockStreamSimulator.java`, in wich the main method is located and has 2 functions: | ||
1. Create/Load the Application Configuration, it does this using Hedera Platform Configuration API. | ||
2. Create a DaggerComponent and instantiate the BlockStreamSimulatorApp class using the DaggerComponent and it registered dependencies. | ||
3. Start the BlockStreamSimulatorApp, contains the orchestration of the different parts of the simulation using generic interfaces and handles the rate of streaming and the exit conditions. | ||
|
||
The BlockStreamSimulatorApp consumes other services that are injected using DaggerComponent, these are: | ||
1. **generator:** responsible for generating blocks, exposes a single interface `BlockStreamManager` and several implementations | ||
1. BlockAsDirBlockStreamManager: generates blocks from a directory, each folder is a block, and block-items are single 'blk' or 'blk.gz' files. | ||
2. BlockAsFileBlockStreamManager: generates blocks from a single file, each file is a block, used to the format of the CN recordings. (since it loads blocks on memory it can stream really fast, really useful for simple streaming tests) | ||
3. BlockAsFileLargeDataSets: similar to BlockAsFileBLockStreamManager, but designed to work with GB folders with thousands of big blocks (since it has a high size block and volume of blocks, is useful for performace, load and stress testing) | ||
2. **grpc:** responsible for the communication with the Block-Node, currently only has 1 interface `PublishStreamGrpcClient` and 1 Implementation, however also exposes a `PublishStreamObserver' | ||
|
||
## Configuration | ||
|
||
There are 2 configuration sets: | ||
1. BlockStreamConfig: contains the configuration for the Block Stream Simulator logic and the generation module. | ||
2. GrpcConfig: contains the configuration for the gRPC communication with the Block-Node. | ||
|
||
### BlockStreamConfig | ||
Uses the prefix `blockStream` so all properties should start with `blockStream.` | ||
|
||
| Key | Description | Default Value | | ||
|--------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------| | ||
| `generationMode` | The desired generation Mode to use, it can only be `DIR` or `AD_HOC` | `DIR` | | ||
| `folderRootPath` | If the generationMode is DIR this will be used as the source of the recording to stream to the Block-Node | `` | | ||
| `delayBetweenBlockItems` | The delay between each block item in nanoseconds | `1_500_000` | | ||
| `managerImplementation` | The desired implementation of the BlockStreamManager to use, it can only be `BlockAsDirBlockStreamManager`, `BlockAsFileBlockStreamManager` or `BlockAsFileLargeDataSets` | `BlockAsFileBlockStreamManager` | | ||
| `maxBlockItemsToStream` | exit condition for the simulator and the circular implementations such as `BlockAsDir` or `BlockAsFile` implementations | `10_000` | | ||
| `paddedLength` | on the `BlockAsFileLargeDataSets` implementation, the length of the padded left zeroes `000001.blk.gz` | 36 | | ||
| `fileExtension` | on the `BlockAsFileLargeDataSets` implementation, the extension of the files to be streamed | `.blk.gz` | | ||
|
||
### GrpcConfig | ||
Uses the prefix `grpc` so all properties should start with `grpc.` | ||
|
||
| Key | Description | Default Value | | ||
|-----------------|----------------------------|---------------| | ||
| `serverAddress` | The host of the Block-Node | `localhost` | | ||
| `port` | The port of the Block-Node | `8080` | | ||
|
||
## Building the Project | ||
|
||
To build the project, run the following command: | ||
|
||
```sh | ||
./gradlew :simulator:build | ||
``` | ||
|
||
## Running the Project | ||
|
||
Usually you will want to run a Block-Node server before the simulator, for that you can use the following commnad: | ||
|
||
```sh | ||
./gradlew :server:run | ||
``` | ||
However we recommend running the block-node server as a docker container: | ||
```sh | ||
./gradlew :server:build :server:createDockerImage :server:startDockerContainer | ||
``` | ||
|
||
Once the project is built, you can run it using the following command: | ||
|
||
```sh | ||
./gradlew :simulator:run | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
simulator/src/main/java/com/hedera/block/simulator/Constants.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
* Copyright (C) 2024 Hedera Hashgraph, LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.hedera.block.simulator; | ||
|
||
public class Constants { | ||
|
||
// The file extension for block files. | ||
public static final String RECORD_EXTENSION = "blk"; | ||
// postfix for gzipped files | ||
public static final String GZ_EXTENSION = ".gz"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
simulator/src/main/java/com/hedera/block/simulator/generator/BlockAsFileLargeDataSets.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/* | ||
* Copyright (C) 2024 Hedera Hashgraph, LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.hedera.block.simulator.generator; | ||
|
||
import static com.hedera.block.simulator.generator.Utils.readFileBytes; | ||
import static java.lang.System.Logger.Level.INFO; | ||
|
||
import com.hedera.block.simulator.config.data.BlockStreamConfig; | ||
import com.hedera.block.simulator.config.types.GenerationMode; | ||
import com.hedera.hapi.block.stream.Block; | ||
import com.hedera.hapi.block.stream.BlockItem; | ||
import com.hedera.pbj.runtime.ParseException; | ||
import com.hedera.pbj.runtime.io.buffer.Bytes; | ||
import edu.umd.cs.findbugs.annotations.NonNull; | ||
import java.io.File; | ||
import java.io.IOException; | ||
import javax.inject.Inject; | ||
|
||
/** A block stream manager that reads blocks from files in a directory. */ | ||
public class BlockAsFileLargeDataSets implements BlockStreamManager { | ||
|
||
private final System.Logger LOGGER = System.getLogger(getClass().getName()); | ||
|
||
private final String blockstreamPath; | ||
private int currentBlockIndex = 0; | ||
private int currentBlockItemIndex = 0; | ||
|
||
private Block currentBlock = null; | ||
private final String formatString; | ||
|
||
/** | ||
* Constructs a new BlockAsFileLargeDataSets instance. | ||
* | ||
* @param config the block stream configuration | ||
*/ | ||
@Inject | ||
public BlockAsFileLargeDataSets(@NonNull BlockStreamConfig config) { | ||
this.blockstreamPath = config.folderRootPath(); | ||
this.formatString = "%0" + config.paddedLength() + "d" + config.fileExtension(); | ||
} | ||
|
||
@Override | ||
public GenerationMode getGenerationMode() { | ||
return GenerationMode.DIR; | ||
} | ||
|
||
@Override | ||
public BlockItem getNextBlockItem() throws IOException, ParseException { | ||
if (currentBlock != null && currentBlock.items().size() > currentBlockItemIndex) { | ||
return currentBlock.items().get(currentBlockItemIndex++); | ||
} else { | ||
currentBlock = getNextBlock(); | ||
if (currentBlock != null) { | ||
currentBlockItemIndex = 0; // Reset for new block | ||
return getNextBlockItem(); | ||
} | ||
} | ||
|
||
return null; // No more blocks/items | ||
} | ||
|
||
@Override | ||
public Block getNextBlock() throws IOException, ParseException { | ||
currentBlockIndex++; | ||
|
||
String nextBlockFileName = String.format(formatString, currentBlockIndex); | ||
File blockFile = new File(blockstreamPath, nextBlockFileName); | ||
|
||
if (blockFile.exists()) { | ||
byte[] blockBytes = readFileBytes(blockFile.toPath()); | ||
|
||
LOGGER.log(INFO, "Loading block: " + blockFile.getName()); | ||
|
||
Block block = Block.PROTOBUF.parse(Bytes.wrap(blockBytes)); | ||
LOGGER.log(INFO, "block loaded with items size= " + block.items().size()); | ||
return block; | ||
} | ||
|
||
return null; // No more blocks found | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.