24
24
import java .io .IOException ;
25
25
import java .nio .file .Files ;
26
26
import java .nio .file .Path ;
27
- import java .util .Collections ;
28
27
import java .util .Optional ;
29
28
30
29
import static com .hedera .block .protos .BlockStreamService .Block ;
30
+ import static com .hedera .block .protos .BlockStreamService .Block .Builder ;
31
31
import static com .hedera .block .protos .BlockStreamService .BlockItem ;
32
32
import static com .hedera .block .server .Constants .BLOCKNODE_STORAGE_ROOT_PATH_KEY ;
33
33
37
37
*/
38
38
public class FileSystemBlockStorage implements BlockStorage <Block , BlockItem > {
39
39
40
+ private final System .Logger LOGGER = System .getLogger (getClass ().getName ());
41
+
40
42
public static final String BLOCK_FILE_EXTENSION = ".blk" ;
41
43
42
44
private final Path blockNodeRootPath ;
43
- private final System .Logger LOGGER = System .getLogger (getClass ().getName ());
45
+
46
+ private long currentIndex = 1 ;
47
+ private Path currentBlockDir ;
44
48
45
49
/**
46
50
* Constructs a FileSystemBlockStorage object.
@@ -50,12 +54,11 @@ public class FileSystemBlockStorage implements BlockStorage<Block, BlockItem> {
50
54
* @throws IOException if an I/O error occurs while initializing the block node root directory
51
55
*/
52
56
public FileSystemBlockStorage (final String key , final Config config ) throws IOException {
53
-
54
57
LOGGER .log (System .Logger .Level .INFO , "Initializing FileSystemBlockStorage" );
55
- LOGGER .log (System .Logger .Level .INFO , config .toString ());
56
58
57
59
blockNodeRootPath = Path .of (config .get (key ).asString ().get ());
58
60
61
+ LOGGER .log (System .Logger .Level .INFO , config .toString ());
59
62
LOGGER .log (System .Logger .Level .INFO , "Block Node Root Path: " + blockNodeRootPath );
60
63
61
64
if (!blockNodeRootPath .isAbsolute ()) {
@@ -79,20 +82,20 @@ public FileSystemBlockStorage(final String key, final Config config) throws IOEx
79
82
/**
80
83
* Writes a block to the filesystem.
81
84
*
82
- * @param blockItem the block to write
83
- * @return the id of the block
84
85
*/
85
86
@ Override
86
- public Optional <Long > write (final BlockItem blockItem , final long blockNumber ) {
87
- final String fullPath = resolvePath (blockNumber );
88
- try (FileOutputStream fos = new FileOutputStream (fullPath )) {
89
- blockItem .writeTo (fos );
90
- LOGGER .log (System .Logger .Level .DEBUG , "Successfully wrote the block file: " + fullPath );
91
-
92
- return Optional .of (blockNumber );
93
- } catch (IOException e ) {
94
- LOGGER .log (System .Logger .Level .ERROR , "Error writing the protobuf to a file" , e );
95
- return Optional .empty ();
87
+ public void write (final BlockItem blockItem ) {
88
+
89
+ try {
90
+ final String blockItemFilePath = getAbsoluteFilePath (blockItem );
91
+ try (FileOutputStream fos = new FileOutputStream (blockItemFilePath )) {
92
+ blockItem .writeTo (fos );
93
+ LOGGER .log (System .Logger .Level .INFO , "Successfully wrote the block item file: {0}" , blockItemFilePath );
94
+ } catch (IOException e ) {
95
+ LOGGER .log (System .Logger .Level .ERROR , "Error writing the protobuf to a file" , e );
96
+ }
97
+ } catch (IOException io ) {
98
+ LOGGER .log (System .Logger .Level .ERROR , "Error calculating the block item path" , io );
96
99
}
97
100
}
98
101
@@ -104,27 +107,82 @@ public Optional<Long> write(final BlockItem blockItem, final long blockNumber) {
104
107
*/
105
108
@ Override
106
109
public Optional <Block > read (final long id ) {
107
- return read (resolvePath (id ));
110
+
111
+ final Builder builder = Block .newBuilder ();
112
+ final Path blockPath = blockNodeRootPath .resolve (String .valueOf (id ));
113
+ return read (blockPath , builder );
108
114
}
109
115
110
- private Optional <Block > read (final String filePath ) {
116
+ private Optional <Block > read (final Path blockPath , final Builder builder ) {
117
+
118
+ // Directly count and add BlockItems into the Block
119
+ // to keep the retrieval process O(BlockItems)
120
+ boolean isEnd = false ;
121
+ for (int i = 1 ;!isEnd ;i ++) {
122
+ final Path blockItemPath = blockPath .resolve (i + BLOCK_FILE_EXTENSION );
123
+ final Optional <BlockItem > blockItemOpt = readBlockItem (blockItemPath .toString ());
124
+ if (blockItemOpt .isPresent ()) {
125
+ builder .addBlockItems (blockItemOpt .get ());
126
+ continue ;
127
+ }
128
+
129
+ isEnd = true ;
130
+ }
131
+
132
+ return Optional .of (builder .build ());
133
+ }
111
134
112
- try (FileInputStream fis = new FileInputStream (filePath )) {
135
+ private Optional <BlockItem > readBlockItem (final String blockItemPath ) {
136
+ try (FileInputStream fis = new FileInputStream (blockItemPath )) {
113
137
return Optional .of (BlockItem .parseFrom (fis ));
114
138
} catch (FileNotFoundException io ) {
115
- LOGGER .log (System .Logger .Level .ERROR , "Error reading file: " + filePath , io );
116
139
return Optional .empty ();
117
140
} catch (IOException io ) {
118
- throw new RuntimeException ("Error reading file: " + filePath , io );
141
+ throw new RuntimeException ("Error reading file: " + blockItemPath , io );
119
142
}
120
143
}
121
144
122
- private String resolvePath (final long blockNumber ) {
145
+ private String getAbsoluteFilePath (final BlockItem blockItem ) throws IOException {
123
146
124
- String fileName = id + BLOCK_FILE_EXTENSION ;
125
- Path fullPath = blockNodeRootPath .resolve (fileName );
126
- LOGGER .log (System .Logger .Level .DEBUG , "Resolved fullPath: " + fullPath );
147
+ if (blockItem .hasBlockHeader ()) {
127
148
128
- return fullPath .toString ();
149
+ // A "block" is a directory of blockItems. Create the "block"
150
+ // based on the block_number
151
+ currentBlockDir = Path .of (String .valueOf (blockItem .getBlockHeader ().getBlockNumber ()));
152
+
153
+ final Path blockPath = blockNodeRootPath .resolve (currentBlockDir );
154
+ createPath (blockPath );
155
+
156
+ // Build the path to the BlockHeader.blk file
157
+ currentIndex = 1 ;
158
+ return blockPath .resolve (currentIndex + BLOCK_FILE_EXTENSION ).toString ();
159
+ }
160
+
161
+ // Build the path to a .blk file
162
+ final Path blockPath = blockNodeRootPath .resolve (currentBlockDir );
163
+ return blockPath .resolve (++currentIndex + BLOCK_FILE_EXTENSION ).toString ();
164
+ }
165
+
166
+ private void createPath (Path blockNodePath ) throws IOException {
167
+ // Initialize the block node root directory if it does not exist
168
+ if (Files .notExists (blockNodePath )) {
169
+ Files .createDirectory (blockNodePath );
170
+ LOGGER .log (
171
+ System .Logger .Level .INFO ,
172
+ "Created block node root directory: " + blockNodePath );
173
+ } else {
174
+ LOGGER .log (
175
+ System .Logger .Level .INFO ,
176
+ "Using existing block node root directory: " + blockNodePath );
177
+ }
129
178
}
179
+
180
+ // private String resolvePath(final long blockNumber) {
181
+ //
182
+ // String fileName = blockNumber + BLOCK_FILE_EXTENSION;
183
+ // Path fullPath = blockNodeRootPath.resolve(fileName);
184
+ // LOGGER.log(System.Logger.Level.DEBUG, "Resolved fullPath: " + fullPath);
185
+ //
186
+ // return fullPath.toString();
187
+ // }
130
188
}
0 commit comments