IGNITE-6577 Check temporary file existence outside lock file during cache start - Fixes #2817.
Signed-off-by: Alexey Goncharuk <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/7a61c15c Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/7a61c15c Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/7a61c15c Branch: refs/heads/ignite-5937 Commit: 7a61c15c746bd77f4bbce05c0db509c467fec68a Parents: bb31a8a Author: dpavlov <[email protected]> Authored: Mon Oct 23 17:08:07 2017 +0300 Committer: Alexey Goncharuk <[email protected]> Committed: Mon Oct 23 17:08:07 2017 +0300 ---------------------------------------------------------------------- .../persistence/file/FilePageStoreManager.java | 62 ++++++++++++-------- .../snapshot/IgniteCacheSnapshotManager.java | 3 + .../wal/serializer/RecordV2Serializer.java | 3 +- .../ignite/internal/util/IgniteUtils.java | 62 +++++++++++--------- 4 files changed, 76 insertions(+), 54 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/7a61c15c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java index aadcee6..1fe22ca 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java @@ -28,6 +28,7 @@ import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -389,43 +390,52 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen File lockF = new File(cacheWorkDir, IgniteCacheSnapshotManager.SNAPSHOT_RESTORE_STARTED_LOCK_FILENAME); - if (lockF.exists()) { - Path tmp = cacheWorkDir.toPath().getParent().resolve(cacheWorkDir.getName() + ".tmp"); + Path cacheWorkDirPath = cacheWorkDir.toPath(); - boolean deleted = U.delete(cacheWorkDir); + Path tmp = cacheWorkDirPath.getParent().resolve(cacheWorkDir.getName() + ".tmp"); - if (Files.exists(tmp) && Files.isDirectory(tmp)) { - U.warn(log, "Ignite node crashed during the snapshot restore process " + - "(there is a snapshot restore lock file left for cache). But old version of cache was saved. " + - "Trying to restore it. Cache - [" + cacheWorkDir.getAbsolutePath() + ']'); + if (Files.exists(tmp) && Files.isDirectory(tmp) && + Files.exists(tmp.resolve(IgniteCacheSnapshotManager.TEMP_FILES_COMPLETENESS_MARKER))) { - try { - Files.move(tmp, cacheWorkDir.toPath()); - } - catch (IOException e) { - throw new IgniteCheckedException(e); - } - } - else { - U.warn(log, "Ignite node crashed during the snapshot restore process " + - "(there is a snapshot restore lock file left for cache). Will remove both the lock file and " + - "incomplete cache directory [cacheDir=" + cacheWorkDir.getAbsolutePath() + ']'); + U.warn(log, "Ignite node crashed during the snapshot restore process " + + "(there is a snapshot restore lock file left for cache). But old version of cache was saved. " + + "Trying to restore it. Cache - [" + cacheWorkDir.getAbsolutePath() + ']'); - if (!deleted) - throw new IgniteCheckedException("Failed to remove obsolete cache working directory " + - "(remove the directory manually and make sure the work folder has correct permissions): " + - cacheWorkDir.getAbsolutePath()); + U.delete(cacheWorkDir); - cacheWorkDir.mkdirs(); + try { + Files.move(tmp, cacheWorkDirPath, StandardCopyOption.ATOMIC_MOVE); + + cacheWorkDirPath.resolve(IgniteCacheSnapshotManager.TEMP_FILES_COMPLETENESS_MARKER).toFile().delete(); + } + catch (IOException e) { + throw new IgniteCheckedException(e); } + } + else if (lockF.exists()) { + U.warn(log, "Ignite node crashed during the snapshot restore process " + + "(there is a snapshot restore lock file left for cache). Will remove both the lock file and " + + "incomplete cache directory [cacheDir=" + cacheWorkDir.getAbsolutePath() + ']'); - if (!cacheWorkDir.exists()) - throw new IgniteCheckedException("Failed to initialize cache working directory " + - "(failed to create, make sure the work folder has correct permissions): " + + boolean deleted = U.delete(cacheWorkDir); + + if (!deleted) + throw new IgniteCheckedException("Failed to remove obsolete cache working directory " + + "(remove the directory manually and make sure the work folder has correct permissions): " + cacheWorkDir.getAbsolutePath()); + + cacheWorkDir.mkdirs(); } else dirExisted = true; + + if (!cacheWorkDir.exists()) + throw new IgniteCheckedException("Failed to initialize cache working directory " + + "(failed to create, make sure the work folder has correct permissions): " + + cacheWorkDir.getAbsolutePath()); + + if (Files.exists(tmp)) + U.delete(tmp); } return dirExisted; http://git-wip-us.apache.org/repos/asf/ignite/blob/7a61c15c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IgniteCacheSnapshotManager.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IgniteCacheSnapshotManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IgniteCacheSnapshotManager.java index 50e6515..5746c17 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IgniteCacheSnapshotManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IgniteCacheSnapshotManager.java @@ -39,6 +39,9 @@ public class IgniteCacheSnapshotManager<T extends SnapshotOperation> extends Gri /** Snapshot started lock filename. */ public static final String SNAPSHOT_RESTORE_STARTED_LOCK_FILENAME = "snapshot-started.loc"; + /** Temp files completeness marker. */ + public static final String TEMP_FILES_COMPLETENESS_MARKER = "finished.tmp"; + /** * Try to start local snapshot operation if it's required by discovery event. * http://git-wip-us.apache.org/repos/asf/ignite/blob/7a61c15c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java index 98804d9..5eb45ac 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java @@ -32,6 +32,7 @@ import org.apache.ignite.internal.processors.cache.persistence.wal.WalSegmentTai import org.apache.ignite.internal.processors.cache.persistence.wal.serializer.io.RecordIO; import org.apache.ignite.internal.util.typedef.F; +import static org.apache.ignite.internal.pagemem.wal.record.WALRecord.*; import static org.apache.ignite.internal.processors.cache.persistence.wal.serializer.RecordV1Serializer.CRC_SIZE; import static org.apache.ignite.internal.processors.cache.persistence.wal.serializer.RecordV1Serializer.REC_TYPE_SIZE; @@ -39,7 +40,7 @@ import static org.apache.ignite.internal.processors.cache.persistence.wal.serial * Record V2 serializer. * Stores records in following format: * <ul> - * <li>Record type from {@code WALRecord.RecordType} incremented by 1</li> + * <li>Record type from {@link RecordType#ordinal()} incremented by 1</li> * <li>WAL pointer to double check consistency</li> * <li>Record length</li> * <li>Data</li> http://git-wip-us.apache.org/repos/asf/ignite/blob/7a61c15c/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java index bdcf87e..d426468 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java @@ -3434,7 +3434,6 @@ public abstract class IgniteUtils { return e; } - /** * Deletes file or directory with all sub-directories and files. * @@ -3443,40 +3442,49 @@ public abstract class IgniteUtils { * {@code false} otherwise */ public static boolean delete(@Nullable File file) { - if (file == null) - return false; - - boolean res = true; - - if (file.isDirectory()) { - File[] files = file.listFiles(); + return file != null && delete(file.toPath()); + } - if (files != null && files.length > 0) { - for (File file1 : files) { - if (file1.isDirectory()) - res &= delete(file1); - else if (file1.getName().endsWith("jar")) { - try { - // Why do we do this? - new JarFile(file1, false).close(); - } - catch (IOException ignore) { - // Ignore it here... - } + /** + * Deletes file or directory with all sub-directories and files. + * + * @param path File or directory to delete. + * @return {@code true} if and only if the file or directory is successfully deleted, + * {@code false} otherwise + */ + public static boolean delete(Path path) { + if (Files.isDirectory(path)) { + try { + try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) { + for (Path innerPath : stream) { + boolean res = delete(innerPath); - res &= file1.delete(); + if (!res) + return false; } - else - res &= file1.delete(); } + } catch (IOException e) { + return false; } + } - res &= file.delete(); + if (path.endsWith("jar")) { + try { + // Why do we do this? + new JarFile(path.toString(), false).close(); + } + catch (IOException ignore) { + // Ignore it here... + } } - else - res = file.delete(); - return res; + try { + Files.delete(path); + + return true; + } catch (IOException e) { + return false; + } } /**
