Skip to content

Commit b63bb9b

Browse files
committed
Bug 38279239 - [37442204->14.1.1.0.23] Snapshot validation passes for snapshots can't be recovered (missing partition folders aren't detected) (14.1.1.0 cl 118395 --> 14.1.1.0 CE)
[git-p4: depot-paths = "//dev/coherence-ce/release/coherence-ce-v14.1.1.0/": change = 118449]
1 parent bd6595f commit b63bb9b

File tree

6 files changed

+272
-37
lines changed

6 files changed

+272
-37
lines changed

prj/coherence-core/src/main/java/com/tangosol/io/FileHelper.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/*
2-
* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
2+
* Copyright (c) 2000, 2025, Oracle and/or its affiliates.
33
*
44
* Licensed under the Universal Permissive License v 1.0 as shown at
5-
* http://oss.oracle.com/licenses/upl.
5+
* https://oss.oracle.com/licenses/upl.
66
*/
77
package com.tangosol.io;
88

@@ -844,6 +844,22 @@ public static String removeExtension(final String filename)
844844
}
845845
}
846846

847+
/**
848+
* Return true if the specified directory is empty.
849+
*
850+
* @param fileDir the directory to check
851+
*
852+
* @return true if the directory is empty
853+
*
854+
* @since 24.09
855+
*/
856+
public static boolean isEmpty(File fileDir)
857+
{
858+
File[] afile = fileDir.listFiles();
859+
860+
return fileDir.isDirectory() && (afile == null || afile.length == 0);
861+
}
862+
847863
// ----- static helper classes ------------------------------------------
848864

849865
/**

prj/coherence-core/src/main/java/com/tangosol/persistence/AbstractPersistenceManager.java

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import com.tangosol.util.Base;
3838
import com.tangosol.util.ClassHelper;
3939
import com.tangosol.util.NullImplementation;
40+
import com.tangosol.util.SimpleMapEntry;
4041

4142
import java.io.DataInputStream;
4243
import java.io.DataOutput;
@@ -51,7 +52,10 @@
5152
import java.nio.channels.FileLock;
5253

5354
import java.util.ArrayList;
55+
import java.util.Arrays;
56+
import java.util.Deque;
5457
import java.util.HashSet;
58+
import java.util.LinkedList;
5559
import java.util.List;
5660
import java.util.Map;
5761
import java.util.Properties;
@@ -567,24 +571,37 @@ public PersistenceTools getPersistenceTools()
567571
throw new IllegalArgumentException("snapshot must have at least one GUID");
568572
}
569573

570-
String sGUID = asGUIDs[0];
571-
int nVersion;
572-
int cPartitions;
574+
int nVersion;
575+
int cPartitions;
576+
FileLock fileLock = null;
577+
String sGUID = null;
573578

574579
PersistentStore<ReadBuffer> store = null;
575580

576581
try
577582
{
583+
Map.Entry<String, FileLock> entry = pickStore(asGUIDs);
584+
fileLock = entry.getValue();
585+
sGUID = entry.getKey();
586+
578587
store = open(sGUID, null);
579588
cPartitions = CachePersistenceHelper.getPartitionCount(store);
580589
nVersion = CachePersistenceHelper.getPersistenceVersion(store);
581590
}
591+
catch (Exception e)
592+
{
593+
throw Base.ensureRuntimeException(e);
594+
}
582595
finally
583596
{
584597
if (store != null)
585598
{
586599
close(sGUID);
587600
}
601+
if (fileLock != null)
602+
{
603+
FileHelper.unlockFile(fileLock);
604+
}
588605
}
589606

590607
OfflinePersistenceInfo info = new OfflinePersistenceInfo(cPartitions, getStorageFormat(),
@@ -593,6 +610,23 @@ public PersistenceTools getPersistenceTools()
593610
return instantiatePersistenceTools(info);
594611
}
595612

613+
private Map.Entry<String, FileLock> pickStore(String[] stores)
614+
{
615+
Deque<String> candidates = new LinkedList<>(Arrays.asList(stores));
616+
String guid;
617+
while((guid = candidates.poll()) != null)
618+
{
619+
File lockDir = getLockDirectory();
620+
File lockFile = new File(lockDir, guid + ".store.lck");
621+
FileLock fileLock = FileHelper.lockFile(lockFile);
622+
if (fileLock != null)
623+
{
624+
return new SimpleMapEntry<>(guid, fileLock);
625+
}
626+
}
627+
throw new RuntimeException("all stores are locked");
628+
}
629+
596630
/**
597631
* {@inheritDoc}
598632
*/

prj/coherence-core/src/main/java/com/tangosol/persistence/CachePersistenceHelper.java

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@
6464
import java.io.Reader;
6565
import java.io.Writer;
6666

67+
import java.lang.reflect.InvocationTargetException;
68+
import java.lang.reflect.Method;
69+
6770
import java.util.ArrayList;
6871
import java.util.List;
6972
import java.util.Set;
@@ -1150,6 +1153,22 @@ public static void resumeService(final Cluster cluster, final String sServiceNam
11501153
* @throws PersistenceException if any errors
11511154
*/
11521155
public static PersistenceTools getSnapshotPersistenceTools(File dirSnapshot)
1156+
{
1157+
return getSnapshotPersistenceTools(dirSnapshot, false);
1158+
}
1159+
1160+
/**
1161+
* Return an implementation specific instance of {@link PersistenceTools} for
1162+
* the given local snapshot directory.
1163+
*
1164+
* @param dirSnapshot the snapshot directory to get tools for
1165+
* @param validation whether to enable snapshot validation
1166+
*
1167+
* @return an implementation specific instance of PersistenceTools
1168+
*
1169+
* @throws PersistenceException if any errors
1170+
*/
1171+
public static PersistenceTools getSnapshotPersistenceTools(File dirSnapshot, boolean validation)
11531172
{
11541173
PersistenceTools tools;
11551174

@@ -1192,7 +1211,7 @@ public static PersistenceTools getSnapshotPersistenceTools(File dirSnapshot)
11921211

11931212
if ("BDB".equals(sPersistenceType))
11941213
{
1195-
tools = new BerkeleyDBManager(dirSnapshot, null, null).getPersistenceTools();
1214+
tools = new BerkeleyDBManager(dirSnapshot, null, null, validation).getPersistenceTools();
11961215
}
11971216
else
11981217
{
@@ -1544,7 +1563,26 @@ public static String[] getFailedSnapshots(PersistenceEnvironment env)
15441563
File dirSnapshot = new File(dirSnapshots, sName);
15451564
try
15461565
{
1547-
getSnapshotPersistenceTools(dirSnapshot).validate();
1566+
PersistenceTools pt = getSnapshotPersistenceTools(dirSnapshot, true);
1567+
try
1568+
{
1569+
// Using reflection because the PersistenceTools interface wasn't updated,
1570+
// and BerkeleyDBManager returns an anonymous class as the PersistenceTools
1571+
// implementation, so casting isn't possible.
1572+
Method validate = pt.getClass().getMethod("validateWithPartitions");
1573+
validate.setAccessible(true);
1574+
String[] checkedPartitions = (String[]) validate.invoke(pt);
1575+
String validationResult = String.format("%s~~~[%s]", sName, String.join(",", checkedPartitions));
1576+
asFailedSnapshots.add(validationResult);
1577+
}
1578+
catch (NoSuchMethodException e)
1579+
{
1580+
getSnapshotPersistenceTools(dirSnapshot, true).validate();
1581+
}
1582+
catch (InvocationTargetException | IllegalAccessException e)
1583+
{
1584+
throw Base.ensureRuntimeException(e);
1585+
}
15481586
}
15491587
catch (RuntimeException e)
15501588
{

0 commit comments

Comments
 (0)