Skip to content

Commit 11e42f8

Browse files
authored
fix: 18722: Backport the fix for 18571 to release 0.60 (#18723)
Signed-off-by: Artem Ananev <[email protected]>
1 parent ee43eb4 commit 11e42f8

File tree

2 files changed

+92
-45
lines changed

2 files changed

+92
-45
lines changed

platform-sdk/swirlds-merkledb/src/main/java/com/swirlds/merkledb/MerkleDbDataSource.java

+14-5
Original file line numberDiff line numberDiff line change
@@ -275,15 +275,19 @@ public MerkleDbDataSource(
275275
hasDiskStoreForHashes = tableConfig.getHashesRamToDiskThreshold() < Long.MAX_VALUE;
276276
final DataFileCompactor hashStoreDiskFileCompactor;
277277
if (hasDiskStoreForHashes) {
278-
final boolean hashIndexEmpty = pathToDiskLocationInternalNodes.size() == 0;
278+
final boolean needRestorePathToDiskLocationInternalNodes = pathToDiskLocationInternalNodes.size() == 0;
279279
final LoadedDataCallback hashRecordLoadedCallback;
280-
if (hashIndexEmpty) {
280+
if (needRestorePathToDiskLocationInternalNodes) {
281281
if (validLeafPathRange.getMaxValidKey() >= 0) {
282282
pathToDiskLocationInternalNodes.updateValidRange(0, validLeafPathRange.getMaxValidKey());
283283
}
284284
hashRecordLoadedCallback = (dataLocation, hashData) -> {
285285
final VirtualHashRecord hashRecord = VirtualHashRecord.parseFrom(hashData);
286-
pathToDiskLocationInternalNodes.put(hashRecord.path(), dataLocation);
286+
final long path = hashRecord.path();
287+
// Old data files may contain entries with paths outside the current virtual node range
288+
if (path <= validLeafPathRange.getMaxValidKey()) {
289+
pathToDiskLocationInternalNodes.put(path, dataLocation);
290+
}
287291
};
288292
} else {
289293
hashRecordLoadedCallback = null;
@@ -332,15 +336,20 @@ public MerkleDbDataSource(
332336
keyToPath.printStats();
333337

334338
final LoadedDataCallback leafRecordLoadedCallback;
335-
final boolean needRestorePathToDiskLocationLeafNodes = pathToDiskLocationLeafNodes.size() == 0;
339+
final boolean needRestorePathToDiskLocationLeafNodes =
340+
(pathToDiskLocationLeafNodes.size() == 0) && (validLeafPathRange.getMinValidKey() > 0);
336341
if (needRestorePathToDiskLocationLeafNodes) {
337342
if (validLeafPathRange.getMaxValidKey() >= 0) {
338343
pathToDiskLocationLeafNodes.updateValidRange(
339344
validLeafPathRange.getMinValidKey(), validLeafPathRange.getMaxValidKey());
340345
}
341346
leafRecordLoadedCallback = (dataLocation, leafData) -> {
342347
final VirtualLeafBytes leafBytes = VirtualLeafBytes.parseFrom(leafData);
343-
pathToDiskLocationLeafNodes.put(leafBytes.path(), dataLocation);
348+
final long path = leafBytes.path();
349+
// Old data files may contain entries with paths outside the current leaf range
350+
if (validLeafPathRange.withinRange(path)) {
351+
pathToDiskLocationLeafNodes.put(path, dataLocation);
352+
}
344353
};
345354
} else {
346355
leafRecordLoadedCallback = null;

platform-sdk/swirlds-merkledb/src/timingSensitive/java/com/swirlds/merkledb/MerkleDbDataSourceTest.java

+78-40
Original file line numberDiff line numberDiff line change
@@ -477,45 +477,65 @@ void snapshotRestoreIndex(final TestType testType) throws IOException {
477477
final Path originalDbPath = testDirectory.resolve("merkledb-snapshotRestoreIndex-" + testType);
478478
final KeySerializer keySerializer = testType.dataType().getKeySerializer();
479479
final ValueSerializer valueSerializer = testType.dataType().getValueSerializer();
480-
createAndApplyDataSource(originalDbPath, tableName, testType, count, 0, dataSource -> {
481-
final int tableId = dataSource.getTableId();
482-
// create some leaves
483-
dataSource.saveRecords(
484-
count,
485-
count * 2,
486-
IntStream.range(0, count * 2).mapToObj(i -> createVirtualInternalRecord(i, i + 1)),
487-
IntStream.range(count, count * 2)
488-
.mapToObj(i -> testType.dataType().createVirtualLeafRecord(i))
489-
.map(r -> r.toBytes(keySerializer, valueSerializer)),
490-
Stream.empty());
491-
// create a snapshot
492-
final Path snapshotDbPath =
493-
testDirectory.resolve("merkledb-snapshotRestoreIndex-" + testType + "_SNAPSHOT");
494-
dataSource.getDatabase().snapshot(snapshotDbPath, dataSource);
495-
// close data source
496-
dataSource.close();
497-
498-
final MerkleDb snapshotDb = MerkleDb.getInstance(snapshotDbPath, CONFIGURATION);
499-
final MerkleDbPaths snapshotPaths = new MerkleDbPaths(snapshotDb.getTableDir(tableName, tableId));
500-
// Delete all indices
501-
Files.delete(snapshotPaths.pathToDiskLocationLeafNodesFile);
502-
Files.delete(snapshotPaths.pathToDiskLocationInternalNodesFile);
503-
// There is no way to use MerkleDbPaths to get bucket index file path
504-
Files.deleteIfExists(snapshotPaths.keyToPathDirectory.resolve(tableName + "_bucket_index.ll"));
505-
506-
final MerkleDbDataSource snapshotDataSource = snapshotDb.getDataSource(tableName, false);
507-
reinitializeDirectMemoryUsage();
508-
IntStream.range(0, count * 2).forEach(i -> assertHash(snapshotDataSource, i, i + 1));
509-
IntStream.range(count, count * 2)
510-
.forEach(i ->
511-
assertLeaf(testType, keySerializer, valueSerializer, snapshotDataSource, i, i, i + 1, i));
512-
// close data source
513-
snapshotDataSource.close();
514-
515-
// check db count
516-
assertEventuallyEquals(
517-
0L, MerkleDbDataSource::getCountOfOpenDatabases, Duration.ofSeconds(1), "Expected no open dbs");
518-
});
480+
final int[] deltas = {-10, 0, 10};
481+
for (int delta : deltas) {
482+
createAndApplyDataSource(originalDbPath, tableName, testType, count + Math.abs(delta), 0, dataSource -> {
483+
final int tableId = dataSource.getTableId();
484+
// create some records
485+
dataSource.saveRecords(
486+
count - 1,
487+
count * 2 - 2,
488+
IntStream.range(0, count * 2 - 1).mapToObj(i -> createVirtualInternalRecord(i, i + 1)),
489+
IntStream.range(count - 1, count * 2 - 1)
490+
.mapToObj(i -> testType.dataType().createVirtualLeafRecord(i))
491+
.map(r -> r.toBytes(keySerializer, valueSerializer)),
492+
Stream.empty());
493+
if (delta != 0) {
494+
// create some more, current leaf path range shifted by delta
495+
dataSource.saveRecords(
496+
count - 1 + delta,
497+
count * 2 - 2 + 2 * delta,
498+
IntStream.range(0, count * 2 - 1 + 2 * delta)
499+
.mapToObj(i -> createVirtualInternalRecord(i, i + 1)),
500+
IntStream.range(count - 1 + delta, count * 2 - 1 + 2 * delta)
501+
.mapToObj(i -> testType.dataType().createVirtualLeafRecord(i))
502+
.map(r -> r.toBytes(keySerializer, valueSerializer)),
503+
Stream.empty());
504+
}
505+
// create a snapshot
506+
final Path snapshotDbPath =
507+
testDirectory.resolve("merkledb-snapshotRestoreIndex-" + testType + "_SNAPSHOT");
508+
dataSource.getDatabase().snapshot(snapshotDbPath, dataSource);
509+
// close data source
510+
dataSource.close();
511+
512+
final MerkleDb snapshotDb = MerkleDb.getInstance(snapshotDbPath, CONFIGURATION);
513+
final MerkleDbPaths snapshotPaths = new MerkleDbPaths(snapshotDb.getTableDir(tableName, tableId));
514+
// Delete all indices
515+
Files.delete(snapshotPaths.pathToDiskLocationLeafNodesFile);
516+
Files.delete(snapshotPaths.pathToDiskLocationInternalNodesFile);
517+
// There is no way to use MerkleDbPaths to get bucket index file path
518+
Files.deleteIfExists(snapshotPaths.keyToPathDirectory.resolve(tableName + "_bucket_index.ll"));
519+
520+
final MerkleDbDataSource snapshotDataSource = snapshotDb.getDataSource(tableName, false);
521+
reinitializeDirectMemoryUsage();
522+
// Check hashes
523+
IntStream.range(0, count * 2 - 1 + 2 * delta).forEach(i -> assertHash(snapshotDataSource, i, i + 1));
524+
assertNullHash(snapshotDataSource, count * 2 + 2 * delta);
525+
// Check leaves
526+
IntStream.range(0, count - 2 + delta).forEach(i -> assertNullLeaf(snapshotDataSource, i));
527+
IntStream.range(count - 1 + delta, count * 2 - 1 + 2 * delta)
528+
.forEach(i -> assertLeaf(
529+
testType, keySerializer, valueSerializer, snapshotDataSource, i, i, i + 1, i));
530+
assertNullLeaf(snapshotDataSource, count * 2 + 2 * delta);
531+
// close data source
532+
snapshotDataSource.close();
533+
534+
// check db count
535+
assertEventuallyEquals(
536+
0L, MerkleDbDataSource::getCountOfOpenDatabases, Duration.ofSeconds(1), "Expected no open dbs");
537+
});
538+
}
519539
}
520540

521541
@Test
@@ -787,7 +807,16 @@ public static void assertHash(final MerkleDbDataSource dataSource, final long pa
787807
try {
788808
assertEqualsAndPrint(hash(i), dataSource.loadHash(path));
789809
} catch (final Exception e) {
790-
e.printStackTrace();
810+
e.printStackTrace(System.err);
811+
fail("Exception should not have been thrown here!");
812+
}
813+
}
814+
815+
public static void assertNullHash(final MerkleDbDataSource dataSource, final long path) {
816+
try {
817+
assertNull(dataSource.loadHash(path));
818+
} catch (final Exception e) {
819+
e.printStackTrace(System.err);
791820
fail("Exception should not have been thrown here!");
792821
}
793822
}
@@ -828,6 +857,15 @@ public static void assertLeaf(
828857
}
829858
}
830859

860+
public static void assertNullLeaf(final MerkleDbDataSource dataSource, final long path) {
861+
try {
862+
assertNull(dataSource.loadLeafRecord(path));
863+
} catch (final Exception e) {
864+
e.printStackTrace(System.err);
865+
fail("Exception should not have been thrown here!");
866+
}
867+
}
868+
831869
public static <T> void assertEqualsAndPrint(final T recordA, final T recordB) {
832870
assertEquals(
833871
recordA == null ? null : recordA.toString(),

0 commit comments

Comments
 (0)