You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ni...@apache.org on 2021/03/26 07:51:37 UTC
[ignite] branch ignite-cdc updated: IGNITE-14360 Refactor
FileLockHolder for reusage (#8905)
This is an automated email from the ASF dual-hosted git repository.
nizhikov pushed a commit to branch ignite-cdc
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/ignite-cdc by this push:
new e579b1e IGNITE-14360 Refactor FileLockHolder for reusage (#8905)
e579b1e is described below
commit e579b1e557c597d159945c252ea1af793046b1ce
Author: Nikolay <ni...@apache.org>
AuthorDate: Fri Mar 26 10:51:20 2021 +0300
IGNITE-14360 Refactor FileLockHolder for reusage (#8905)
---
.../cache/persistence/FileLockHolder.java | 202 +++++++++++++++++++++
.../GridCacheDatabaseSharedManager.java | 169 +++--------------
.../filename/PdsConsistentIdProcessor.java | 22 +--
.../persistence/filename/PdsFolderSettings.java | 8 +-
4 files changed, 238 insertions(+), 163 deletions(-)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/FileLockHolder.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/FileLockHolder.java
new file mode 100644
index 0000000..b7b3d5c
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/FileLockHolder.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.persistence;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.OverlappingFileLockException;
+import java.nio.file.Paths;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/**
+ * Abstract file lock holder.
+ * Implementations should provide {@link #lockId()} that will appear in error message for concurrent processes
+ * that will try to lock the same file and {@link #warningMessage(String)} to print on each lock try.
+ *
+ * @see GridCacheDatabaseSharedManager.NodeFileLockHolder
+ */
+public abstract class FileLockHolder implements AutoCloseable {
+ /** Lock file name. */
+ private static final String lockFileName = "lock";
+
+ /** File. */
+ private final File file;
+
+ /** Channel. */
+ private final RandomAccessFile lockFile;
+
+ /** Lock. */
+ private volatile FileLock lock;
+
+ /** Logger. */
+ private final IgniteLogger log;
+
+ /**
+ * @param rootDir Root directory for lock file.
+ * @param log Log.
+ */
+ protected FileLockHolder(String rootDir, IgniteLogger log) {
+ try {
+ file = Paths.get(rootDir, lockFileName).toFile();
+
+ lockFile = new RandomAccessFile(file, "rw");
+
+ this.log = log;
+ }
+ catch (IOException e) {
+ throw new IgniteException(e);
+ }
+ }
+
+ /**
+ * This id will appear in error message of concurrent processes that will try to lock on the same file.
+ *
+ * @return Lock ID to store in the file.
+ */
+ public abstract String lockId();
+
+ /**
+ * @param lockId Existing lock id.
+ * @return Warning message.
+ */
+ protected abstract String warningMessage(String lockId);
+
+ /**
+ * @param lockWaitTimeMillis During which time thread will try capture file lock.
+ * @throws IgniteCheckedException If failed to capture file lock.
+ */
+ public void tryLock(long lockWaitTimeMillis) throws IgniteCheckedException {
+ assert lockFile != null;
+
+ FileChannel ch = lockFile.getChannel();
+
+ String failMsg;
+
+ try {
+ String content = null;
+
+ // Try to get lock, if not available wait 1 sec and re-try.
+ for (int i = 0; i < lockWaitTimeMillis; i += 1000) {
+ try {
+ lock = ch.tryLock(0, 1, false);
+
+ if (lock != null && lock.isValid()) {
+ writeContent(lockId());
+
+ return;
+ }
+ }
+ catch (OverlappingFileLockException ignore) {
+ if (content == null)
+ content = readContent();
+
+ log.warning(warningMessage(content));
+ }
+
+ U.sleep(1000);
+ }
+
+ if (content == null)
+ content = readContent();
+
+ failMsg = "Failed to acquire file lock [holder=" + content + ", time=" + (lockWaitTimeMillis / 1000) +
+ " sec, path=" + file.getAbsolutePath() + ']';
+ }
+ catch (Exception e) {
+ throw new IgniteCheckedException(e);
+ }
+
+ if (failMsg != null)
+ throw new IgniteCheckedException(failMsg);
+ }
+
+ /**
+ * Write node id (who captured lock) into lock file.
+ *
+ * @param content Node id.
+ * @throws IOException if some fail while write node it.
+ */
+ private void writeContent(String content) throws IOException {
+ FileChannel ch = lockFile.getChannel();
+
+ byte[] bytes = content.getBytes();
+
+ ByteBuffer buf = ByteBuffer.allocate(bytes.length);
+ buf.put(bytes);
+
+ buf.flip();
+
+ ch.write(buf, 1);
+
+ ch.force(false);
+ }
+
+ /**
+ *
+ */
+ private String readContent() throws IOException {
+ FileChannel ch = lockFile.getChannel();
+
+ ByteBuffer buf = ByteBuffer.allocate((int)(ch.size() - 1));
+
+ ch.read(buf, 1);
+
+ String content = new String(buf.array());
+
+ buf.clear();
+
+ return content;
+ }
+
+ /**
+ * Locked or not.
+ */
+ public boolean isLocked() {
+ return lock != null && lock.isValid();
+ }
+
+ /**
+ * Releases file lock
+ */
+ public void release() {
+ U.releaseQuiet(lock);
+ }
+
+ /**
+ * Closes file channel
+ */
+ @Override public void close() {
+ release();
+
+ U.closeQuiet(lockFile);
+ }
+
+ /**
+ * @return Absolute path to lock file.
+ */
+ public String lockPath() {
+ return file.getAbsolutePath();
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
index 8c0228e..15557ec 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
@@ -19,15 +19,10 @@ package org.apache.ignite.internal.processors.cache.persistence;
import java.io.File;
import java.io.IOException;
-import java.io.RandomAccessFile;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.nio.channels.FileChannel;
-import java.nio.channels.FileLock;
-import java.nio.channels.OverlappingFileLockException;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -299,7 +294,7 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan
* Lock holder for compatible folders mode. Null if lock holder was created at start node. <br>
* In this case lock is held on PDS resover manager and it is not required to manage locking here
*/
- @Nullable private FileLockHolder fileLockHolder;
+ @Nullable private NodeFileLockHolder fileLockHolder;
/** Lock wait time. */
private final long lockWaitTime;
@@ -554,7 +549,7 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan
() -> cpFreqDeviation.getOrDefault(DEFAULT_CHECKPOINT_DEVIATION)
);
- final FileLockHolder preLocked = kernalCtx.pdsFolderResolver()
+ final NodeFileLockHolder preLocked = kernalCtx.pdsFolderResolver()
.resolveFolders()
.getLockedFileLockHolder();
@@ -735,12 +730,12 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan
/**
* @param preLocked Pre-locked file lock holder.
*/
- private void acquireFileLock(FileLockHolder preLocked) throws IgniteCheckedException {
+ private void acquireFileLock(NodeFileLockHolder preLocked) throws IgniteCheckedException {
if (cctx.kernalContext().clientNode())
return;
fileLockHolder = preLocked == null ?
- new FileLockHolder(storeMgr.workDir().getPath(), cctx.kernalContext(), log) : preLocked;
+ new NodeFileLockHolder(storeMgr.workDir().getPath(), cctx.kernalContext(), log) : preLocked;
if (!fileLockHolder.isLocked()) {
if (log.isDebugEnabled())
@@ -2945,53 +2940,25 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan
}
/**
- *
+ * Node file lock holder.
*/
- public static class FileLockHolder implements AutoCloseable {
- /** Lock file name. */
- private static final String lockFileName = "lock";
-
- /** File. */
- private File file;
-
- /** Channel. */
- private RandomAccessFile lockFile;
-
- /** Lock. */
- private volatile FileLock lock;
-
+ public static class NodeFileLockHolder extends FileLockHolder {
/** Kernal context to generate Id of locked node in file. */
- @NotNull private GridKernalContext ctx;
-
- /** Logger. */
- private IgniteLogger log;
+ @NotNull private final GridKernalContext ctx;
/**
- * @param path Path.
+ * @param rootDir Root directory for lock file.
+ * @param ctx Kernal context.
+ * @param log Log.
*/
- public FileLockHolder(String path, @NotNull GridKernalContext ctx, IgniteLogger log) {
- try {
- file = Paths.get(path, lockFileName).toFile();
-
- lockFile = new RandomAccessFile(file, "rw");
+ public NodeFileLockHolder(String rootDir, @NotNull GridKernalContext ctx, IgniteLogger log) {
+ super(rootDir, log);
- this.ctx = ctx;
- this.log = log;
- }
- catch (IOException e) {
- throw new IgniteException(e);
- }
+ this.ctx = ctx;
}
- /**
- * @param lockWaitTimeMillis During which time thread will try capture file lock.
- * @throws IgniteCheckedException If failed to capture file lock.
- */
- public void tryLock(long lockWaitTimeMillis) throws IgniteCheckedException {
- assert lockFile != null;
-
- FileChannel ch = lockFile.getChannel();
-
+ /** {@inheritDoc} */
+ @Override public String lockId() {
SB sb = new SB();
//write node id
@@ -3022,108 +2989,14 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan
sb.a("]");
- String failMsg;
-
- try {
- String content = null;
-
- // Try to get lock, if not available wait 1 sec and re-try.
- for (int i = 0; i < lockWaitTimeMillis; i += 1000) {
- try {
- lock = ch.tryLock(0, 1, false);
-
- if (lock != null && lock.isValid()) {
- writeContent(sb.toString());
-
- return;
- }
- }
- catch (OverlappingFileLockException ignore) {
- if (content == null)
- content = readContent();
-
- log.warning("Failed to acquire file lock. Will try again in 1s " +
- "[nodeId=" + ctx.localNodeId() + ", holder=" + content +
- ", path=" + file.getAbsolutePath() + ']');
- }
-
- U.sleep(1000);
- }
-
- if (content == null)
- content = readContent();
-
- failMsg = "Failed to acquire file lock [holder=" + content + ", time=" + (lockWaitTimeMillis / 1000) +
- " sec, path=" + file.getAbsolutePath() + ']';
- }
- catch (Exception e) {
- throw new IgniteCheckedException(e);
- }
-
- if (failMsg != null)
- throw new IgniteCheckedException(failMsg);
- }
-
- /**
- * Write node id (who captured lock) into lock file.
- *
- * @param content Node id.
- * @throws IOException if some fail while write node it.
- */
- private void writeContent(String content) throws IOException {
- FileChannel ch = lockFile.getChannel();
-
- byte[] bytes = content.getBytes();
-
- ByteBuffer buf = ByteBuffer.allocate(bytes.length);
- buf.put(bytes);
-
- buf.flip();
-
- ch.write(buf, 1);
-
- ch.force(false);
+ return sb.toString();
}
- /**
- *
- */
- private String readContent() throws IOException {
- FileChannel ch = lockFile.getChannel();
-
- ByteBuffer buf = ByteBuffer.allocate((int)(ch.size() - 1));
-
- ch.read(buf, 1);
-
- String content = new String(buf.array());
-
- buf.clear();
-
- return content;
- }
-
- /** Locked or not. */
- public boolean isLocked() {
- return lock != null && lock.isValid();
- }
-
- /** Releases file lock */
- public void release() {
- U.releaseQuiet(lock);
- }
-
- /** Closes file channel */
- @Override public void close() {
- release();
-
- U.closeQuiet(lockFile);
- }
-
- /**
- * @return Absolute path to lock file.
- */
- private String lockPath() {
- return file.getAbsolutePath();
+ /** {@inheritDoc} */
+ @Override protected String warningMessage(String lockId) {
+ return "Failed to acquire file lock. Will try again in 1s " +
+ "[nodeId=" + ctx.localNodeId() + ", holder=" + lockId +
+ ", path=" + lockPath() + ']';
}
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/PdsConsistentIdProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/PdsConsistentIdProcessor.java
index 951a2e1..35f06dd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/PdsConsistentIdProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/PdsConsistentIdProcessor.java
@@ -35,7 +35,7 @@ import org.apache.ignite.configuration.DataStorageConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.GridKernalContext;
import org.apache.ignite.internal.processors.GridProcessorAdapter;
-import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
+import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager.NodeFileLockHolder;
import org.apache.ignite.internal.util.typedef.internal.A;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.SB;
@@ -179,7 +179,7 @@ public class PdsConsistentIdProcessor extends GridProcessorAdapter implements Pd
// If such a folder exists, we start up with this ID (compatibility mode)
final String subFolder = U.maskForFileName(consistentId.toString());
- final GridCacheDatabaseSharedManager.FileLockHolder oldStyleFolderLockHolder = tryLock(new File(pstStoreBasePath, subFolder));
+ final NodeFileLockHolder oldStyleFolderLockHolder = tryLock(new File(pstStoreBasePath, subFolder));
if (oldStyleFolderLockHolder != null)
return new PdsFolderSettings(pstStoreBasePath,
@@ -199,7 +199,7 @@ public class PdsConsistentIdProcessor extends GridProcessorAdapter implements Pd
}
for (FolderCandidate next : getNodeIndexSortedCandidates(pstStoreBasePath)) {
- final GridCacheDatabaseSharedManager.FileLockHolder fileLockHolder = tryLock(next.subFolderFile());
+ final NodeFileLockHolder fileLockHolder = tryLock(next.subFolderFile());
if (fileLockHolder != null) {
if (log.isInfoEnabled())
@@ -214,7 +214,7 @@ public class PdsConsistentIdProcessor extends GridProcessorAdapter implements Pd
}
// was not able to find free slot, allocating new
- try (final GridCacheDatabaseSharedManager.FileLockHolder rootDirLock = lockRootDirectory(pstStoreBasePath)) {
+ try (final NodeFileLockHolder rootDirLock = lockRootDirectory(pstStoreBasePath)) {
final List<FolderCandidate> sortedCandidates = getNodeIndexSortedCandidates(pstStoreBasePath);
final int nodeIdx = sortedCandidates.isEmpty() ? 0 : (sortedCandidates.get(sortedCandidates.size() - 1).nodeIndex() + 1);
@@ -327,7 +327,7 @@ public class PdsConsistentIdProcessor extends GridProcessorAdapter implements Pd
final UUID uuid = UUID.randomUUID();
final String consIdBasedFolder = genNewStyleSubfolderName(nodeIdx, uuid);
final File newRandomFolder = U.resolveWorkDirectory(pstStoreBasePath.getAbsolutePath(), consIdBasedFolder, false); //mkdir here
- final GridCacheDatabaseSharedManager.FileLockHolder fileLockHolder = tryLock(newRandomFolder);
+ final NodeFileLockHolder fileLockHolder = tryLock(newRandomFolder);
if (fileLockHolder != null) {
if (log.isInfoEnabled())
@@ -362,10 +362,10 @@ public class PdsConsistentIdProcessor extends GridProcessorAdapter implements Pd
* @return locked directory, should be released and closed later
* @throws IgniteCheckedException if failed
*/
- @NotNull private GridCacheDatabaseSharedManager.FileLockHolder lockRootDirectory(File pstStoreBasePath)
+ @NotNull private NodeFileLockHolder lockRootDirectory(File pstStoreBasePath)
throws IgniteCheckedException {
- GridCacheDatabaseSharedManager.FileLockHolder rootDirLock;
+ NodeFileLockHolder rootDirLock;
int retry = 0;
while ((rootDirLock = tryLock(pstStoreBasePath)) == null) {
@@ -414,13 +414,13 @@ public class PdsConsistentIdProcessor extends GridProcessorAdapter implements Pd
* @return non null holder if lock was successful, null in case lock failed. If directory does not exist method will
* always fail to lock.
*/
- private GridCacheDatabaseSharedManager.FileLockHolder tryLock(File dbStoreDirWithSubdirectory) {
+ private NodeFileLockHolder tryLock(File dbStoreDirWithSubdirectory) {
if (!dbStoreDirWithSubdirectory.exists())
return null;
final String path = dbStoreDirWithSubdirectory.getAbsolutePath();
- final GridCacheDatabaseSharedManager.FileLockHolder fileLockHolder
- = new GridCacheDatabaseSharedManager.FileLockHolder(path, ctx, log);
+ final NodeFileLockHolder fileLockHolder
+ = new NodeFileLockHolder(path, ctx, log);
try {
fileLockHolder.tryLock(1000);
@@ -500,7 +500,7 @@ public class PdsConsistentIdProcessor extends GridProcessorAdapter implements Pd
/** {@inheritDoc} */
@Override public void stop(boolean cancel) throws IgniteCheckedException {
if (settings != null) {
- final GridCacheDatabaseSharedManager.FileLockHolder fileLockHolder = settings.getLockedFileLockHolder();
+ final NodeFileLockHolder fileLockHolder = settings.getLockedFileLockHolder();
if (fileLockHolder != null)
fileLockHolder.close();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/PdsFolderSettings.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/PdsFolderSettings.java
index c47cbc9..72e0720 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/PdsFolderSettings.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/PdsFolderSettings.java
@@ -19,7 +19,7 @@ package org.apache.ignite.internal.processors.cache.persistence.filename;
import java.io.File;
import java.io.Serializable;
-import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
+import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager.NodeFileLockHolder;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.jetbrains.annotations.NotNull;
@@ -48,7 +48,7 @@ public class PdsFolderSettings {
* directory. This value is to be used at activate instead of locking. <br> May be null in case preconfigured
* consistent ID is used or in case lock holder was already taken by other processor.
*/
- @Nullable private final GridCacheDatabaseSharedManager.FileLockHolder fileLockHolder;
+ @Nullable private final NodeFileLockHolder fileLockHolder;
/**
* Indicates if compatible mode is enabled, in that case all sub folders are generated from consistent ID without
@@ -68,7 +68,7 @@ public class PdsFolderSettings {
public PdsFolderSettings(@Nullable final File persistentStoreRootPath,
final String folderName,
final Serializable consistentId,
- @Nullable final GridCacheDatabaseSharedManager.FileLockHolder fileLockHolder,
+ @Nullable final NodeFileLockHolder fileLockHolder,
final boolean compatible) {
this.consistentId = consistentId;
@@ -125,7 +125,7 @@ public class PdsFolderSettings {
*
* @return File lock holder with prelocked db directory.
*/
- @Nullable public GridCacheDatabaseSharedManager.FileLockHolder getLockedFileLockHolder() {
+ @Nullable public NodeFileLockHolder getLockedFileLockHolder() {
return fileLockHolder;
}