8
8
import java .io .IOException ;
9
9
import java .lang .System .Logger .Level ;
10
10
import java .nio .file .Files ;
11
+ import java .util .ArrayList ;
11
12
import java .util .List ;
12
13
import java .util .Objects ;
13
14
import java .util .concurrent .CopyOnWriteArrayList ;
21
22
import org .hiero .block .node .spi .historicalblocks .BlockAccessor ;
22
23
import org .hiero .block .node .spi .historicalblocks .BlockProviderPlugin ;
23
24
import org .hiero .block .node .spi .historicalblocks .BlockRangeSet ;
25
+ import org .hiero .block .node .spi .historicalblocks .HistoricalBlockFacility ;
24
26
import org .hiero .block .node .spi .historicalblocks .LongRange ;
25
27
26
28
/**
@@ -195,9 +197,13 @@ public BlockRangeSet availableBlocks() {
195
197
*/
196
198
@ Override
197
199
public void handlePersisted (PersistedNotification notification ) {
200
+ // all operations here until we release the caller thread are queued up
201
+ // by the block messaging facility, so we can safely perform
202
+ // calculations and decide if we will submit or not a task
198
203
if (notification .blockProviderPriority () > defaultPriority ()) {
199
204
attemptZipping ();
200
- } // todo this is not enough of an assertion that the blocks will be coming from the right place
205
+ }
206
+ // @todo(1069) this is not enough of an assertion that the blocks will be coming from the right place
201
207
// as notifications are async and things can happen, when we get the accessors later, we should
202
208
// be able to get accessors only from places that have higher priority than us. We should probably
203
209
// have that as a feature in the block accessor api. (meaning we should be able to query the
@@ -207,12 +213,20 @@ public void handlePersisted(PersistedNotification notification) {
207
213
// ==== Private Methods ============================================================================================
208
214
private void attemptZipping () {
209
215
// compute the min and max block in next batch to zip
210
- long minBlockNumber = availableBlocks ().max () + 1 ;
216
+ // since we ensure no gaps in the zip file are possible, and also we
217
+ // have a power of 10 number of blocks per zip file, it is safe to
218
+ // simply add +1 to the latest available block number and have that as
219
+ // the start of the next batch of blocks to zip
220
+ long minBlockNumber = availableBlocks .max () + 1 ;
211
221
long maxBlockNumber = minBlockNumber + numberOfBlocksPerZipFile - 1 ;
212
- // check all those blocks are available
222
+ // make sure the historical block facility has a higher max than our
223
+ // desired batch max
213
224
final BlockRangeSet historicalAvailable =
214
225
context .historicalBlockProvider ().availableBlocks ();
215
226
// while we can zip blocks, we must keep zipping
227
+ // we loop here because the historical block facility can have
228
+ // multiple batches of blocks available for zipping potentially, so we
229
+ // need to queue them all up
216
230
while (historicalAvailable .max () >= maxBlockNumber ) {
217
231
if (historicalAvailable .contains (minBlockNumber , maxBlockNumber )) {
218
232
final LongRange batchRange = new LongRange (minBlockNumber , maxBlockNumber );
@@ -234,17 +248,19 @@ private void attemptZipping() {
234
248
private void startMovingBatchOfBlocksToZipFile (final LongRange batchRange ) {
235
249
// check if the batch of blocks is already in progress
236
250
if (inProgressZipRanges .contains (batchRange )) {
251
+ // if the batch is in progress, we must not submit a task
237
252
LOGGER .log (
238
253
System .Logger .Level .DEBUG ,
239
254
"Batch of blocks[{%1} -> {%2}] is already in progress" ,
240
255
batchRange .start (),
241
256
batchRange .end ());
242
- return ;
257
+ } else {
258
+ // if the batch is not in progress, we must submit a task
259
+ // add the batch of blocks to the in progress ranges
260
+ inProgressZipRanges .add (batchRange );
261
+ // move the batch of blocks to a zip file (submit a task)
262
+ zipMoveExecutorService .submit (() -> moveBatchOfBlocksToZipFile (batchRange ));
243
263
}
244
- // add the batch of blocks to the in progress ranges
245
- inProgressZipRanges .add (batchRange );
246
- // move the batch of blocks to a zip file
247
- zipMoveExecutorService .submit (() -> moveBatchOfBlocksToZipFile (batchRange ));
248
264
}
249
265
250
266
/**
@@ -253,47 +269,70 @@ private void startMovingBatchOfBlocksToZipFile(final LongRange batchRange) {
253
269
* @param batchRange The range of blocks to move to zip file.
254
270
*/
255
271
private void moveBatchOfBlocksToZipFile (final LongRange batchRange ) {
256
- final long batchFirstBlockNumber = batchRange .start ();
257
- final long batchLastBlockNumber = batchRange .end ();
258
- // move the batch of blocks to a zip file
259
272
try {
260
- LOGGER .log (
261
- System .Logger .Level .DEBUG ,
262
- "Moving batch of blocks[%d -> %d] to zip file" ,
263
- batchFirstBlockNumber ,
264
- batchLastBlockNumber );
265
-
266
- // Write the zip file and get result with file size
267
- final long zipFileSize = zipBlockArchive .writeNewZipFile (batchFirstBlockNumber );
268
- // Metrics updates
269
- // Update total bytes stored with the new zip file size
270
- totalBytesStored .addAndGet (zipFileSize );
271
- // Increment the blocks written counter
272
- long blockCount = batchLastBlockNumber - batchFirstBlockNumber + 1 ;
273
- blocksWrittenCounter .add (blockCount );
274
- } catch (final IOException e ) {
275
- LOGGER .log (
276
- System .Logger .Level .ERROR ,
277
- "Failed to move batch of blocks[" + batchFirstBlockNumber + " -> " + batchLastBlockNumber
278
- + "] to zip file" ,
279
- e );
280
- return ;
273
+ // first off, let's create our batch of blocks
274
+ final long batchFirstBlockNumber = batchRange .start ();
275
+ final long batchLastBlockNumber = batchRange .end ();
276
+ final List <BlockAccessor > batch = new ArrayList <>(numberOfBlocksPerZipFile );
277
+ final HistoricalBlockFacility historicalBlockFacility = context .historicalBlockProvider ();
278
+ // gather batch, if there are no gaps, then we can proceed with zipping
279
+ for (long blockNumber = batchFirstBlockNumber ; blockNumber <= batchLastBlockNumber ; blockNumber ++) {
280
+ final BlockAccessor currentAccessor = historicalBlockFacility .block (blockNumber );
281
+ if (currentAccessor == null ) {
282
+ break ;
283
+ } else {
284
+ batch .add (currentAccessor );
285
+ }
286
+ }
287
+ // if there are any gaps, then we cannot zip the batch
288
+ if (batch .size () != numberOfBlocksPerZipFile ) {
289
+ // we have a gap in the batch, so we cannot zip it
290
+ LOGGER .log (
291
+ System .Logger .Level .DEBUG ,
292
+ "Batch of blocks[%d -> %d] has a gap, skipping zipping" ,
293
+ batchFirstBlockNumber ,
294
+ batchLastBlockNumber );
295
+ } else {
296
+ // move the batch of blocks to a zip file
297
+ try {
298
+ LOGGER .log (
299
+ System .Logger .Level .DEBUG ,
300
+ "Moving batch of blocks[%d -> %d] to zip file" ,
301
+ batchFirstBlockNumber ,
302
+ batchLastBlockNumber );
303
+ // Write the zip file and get result with file size
304
+ final long zipFileSize = zipBlockArchive .writeNewZipFile (batch );
305
+ // Metrics updates
306
+ // Update total bytes stored with the new zip file size
307
+ totalBytesStored .addAndGet (zipFileSize );
308
+ // Increment the blocks written counter
309
+ blocksWrittenCounter .add (numberOfBlocksPerZipFile );
310
+ } catch (final IOException e ) {
311
+ LOGGER .log (
312
+ System .Logger .Level .ERROR ,
313
+ "Failed to move batch of blocks[" + batchFirstBlockNumber + " -> " + batchLastBlockNumber
314
+ + "] to zip file" ,
315
+ e );
316
+ return ;
317
+ }
318
+ // if we have reached here, then the batch of blocks has been zipped,
319
+ // now we need to make some updates
320
+ // update the first and last block numbers
321
+ availableBlocks .add (batchFirstBlockNumber , batchLastBlockNumber );
322
+ // log done
323
+ LOGGER .log (
324
+ Level .INFO ,
325
+ "Moved batch of blocks[%d -> %d] to zip file" ,
326
+ batchFirstBlockNumber ,
327
+ batchLastBlockNumber );
328
+ // now all the blocks are in the zip file and accessible, send notification
329
+ context .blockMessaging ()
330
+ .sendBlockPersisted (new PersistedNotification (
331
+ batchFirstBlockNumber , batchLastBlockNumber , defaultPriority ()));
332
+ }
333
+ } finally {
334
+ // always make sure to remove the batch of blocks from in progress ranges
335
+ inProgressZipRanges .remove (batchRange );
281
336
}
282
- // if we have reached here, then the batch of blocks has been zipped,
283
- // now we need to make some updates
284
- // update the first and last block numbers
285
- availableBlocks .add (batchFirstBlockNumber , batchLastBlockNumber );
286
- // log done
287
- LOGGER .log (
288
- System .Logger .Level .INFO ,
289
- "Moved batch of blocks[%d -> %d] to zip file" ,
290
- batchFirstBlockNumber ,
291
- batchLastBlockNumber );
292
- // now all the blocks are in the zip file and accessible, send notification
293
- context .blockMessaging ()
294
- .sendBlockPersisted (
295
- new PersistedNotification (batchFirstBlockNumber , batchLastBlockNumber , defaultPriority ()));
296
- // remove the batch of blocks from in progress ranges
297
- inProgressZipRanges .remove (batchRange );
298
337
}
299
338
}
0 commit comments