From ba60631e7642a8a39f490f665c1863a700152e9b Mon Sep 17 00:00:00 2001
From: Jan Lahoda
Date: Mon, 30 Oct 2023 21:48:52 +0100
Subject: [PATCH 1/6] [NETBEANS-4962] Adding ability to disable hard-locking
files using lock files.
---
.../filebasedfs/fileobjects/LockForFile.java | 168 ++++++++++++++----
.../fileobjects/WriteLockUtils.java | 91 ----------
.../masterfs/filebasedfs/utils/FileInfo.java | 4 +-
.../filebasedfs/BaseFileObjectTestHid.java | 4 +-
.../fileobjects/FolderObjTest.java | 2 +-
.../fileobjects/LockForFileInMemoryTest.java | 50 ++++++
.../fileobjects/LockForFileTest.java | 21 ++-
.../fileobjects/StatFilesTest.java | 2 +
.../filebasedfs/fileobjects/TestUtils.java | 21 +++
9 files changed, 221 insertions(+), 142 deletions(-)
delete mode 100644 platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/WriteLockUtils.java
create mode 100644 platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileInMemoryTest.java
diff --git a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFile.java b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFile.java
index 659ac2c69c5b..60dd31f70444 100644
--- a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFile.java
+++ b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFile.java
@@ -26,8 +26,11 @@
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import org.netbeans.modules.masterfs.filebasedfs.utils.FileChangedManager;
import org.netbeans.modules.masterfs.filebasedfs.utils.Utils;
import org.openide.filesystems.FileAlreadyLockedException;
@@ -35,6 +38,8 @@
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.Exceptions;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.ServiceProvider;
/**
* FileLock with support for fine grained hard locking to ensure better performance
@@ -43,10 +48,11 @@
public class LockForFile extends FileLock {
private static final ConcurrentHashMap name2Namesakes = new ConcurrentHashMap<>();
- private static final String PREFIX = ".LCK";
- private static final String SUFFIX = "~";
+ static final String PREFIX = ".LCK";
+ static final String SUFFIX = "~";
+ private static final Logger LOGGER = Logger.getLogger(LockForFile.class.getName());
private File file;
- private File lock;
+ private HardLockPath lock;
private boolean valid = false;
static {
@@ -79,7 +85,7 @@ private static LockForFile registerLock(LockForFile result) throws IOException,
File file = result.getFile();
Namesakes namesakes = new Namesakes();
Namesakes oldNamesakes = name2Namesakes.putIfAbsent(file.getName(), namesakes);
- if (oldNamesakes != null) {
+ if (oldNamesakes != null) {
namesakes = oldNamesakes;
}
if (namesakes.putInstance(file, result) == null) {
@@ -152,18 +158,17 @@ boolean hardLock() throws IOException {
if (isHardLocked()) {
throw new FileAlreadyLockedException(file.getAbsolutePath());
}
- File hardLock = getLock();
- hardLock.getParentFile().mkdirs();
- hardLock.createNewFile();
- try (OutputStream os = Files.newOutputStream(hardLock.toPath())) {
- os.write(getFile().getAbsolutePath().getBytes());
- return true;
- }
+
+ HardLockPath hardLock = getLock();
+
+ HardLockRegistry.getInstance().doHardLock(hardLock, getFile().getAbsolutePath());
+
+ return true;
}
/*not private for tests*/
boolean hardUnlock() {
- return getLock().delete();
+ return HardLockRegistry.getInstance().doHardUnlock(getLock());
}
private static synchronized boolean hardUnlockAll() {
@@ -185,7 +190,7 @@ private static synchronized boolean hardUnlockAll() {
return result;
}
- public File getLock() {
+ public HardLockPath getLock() {
return lock;
}
@@ -194,25 +199,9 @@ public File getFile() {
}
public File getHardLock() {
- if (FileChangedManager.getInstance().exists(lock)) {
- InputStream is = null;
- try {
- is = new FileInputStream(lock);
- byte[] path = new byte[is.available()];
- if (path.length > 0 && is.read(path) == path.length) {
- return new File(new String(path));
- }
- } catch (IOException ex) {
- Exceptions.printStackTrace(ex);
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException ex) {
- Exceptions.printStackTrace(ex);
- }
- }
- }
+ String content = HardLockRegistry.getInstance().getHardLockContent(lock);
+ if (content != null) {
+ return new File(content);
}
return null;
}
@@ -226,7 +215,7 @@ public void rename() {
}
- public static File getLockFile(File file) {
+ public static HardLockPath getLockFile(File file) {
file = FileUtil.normalizeFile(file);
final File parentFile = file.getParentFile();
@@ -238,7 +227,7 @@ public static File getLockFile(File file) {
final String lckName = sb.toString();
final File lck = new File(parentFile, lckName);
- return lck;
+ return new HardLockPath(lck.getAbsoluteFile());
}
@Override
@@ -286,7 +275,7 @@ private void hardLock() throws IOException {
if (reference != null) {
LockForFile lockForFile = reference.get();
if (lockForFile != null) {
- if (!FileChangedManager.getInstance().exists(lockForFile.getLock())) {
+ if (!HardLockRegistry.getInstance().hardLockExists(lockForFile.getLock())) {
lockForFile.hardLock();
}
}
@@ -294,4 +283,113 @@ private void hardLock() throws IOException {
}
}
}
+
+ public static boolean hasActiveLockFileSigns(final String filename) {
+ return filename.startsWith(PREFIX) && filename.endsWith(SUFFIX);
+ }
+
+ public static final class HardLockPath {
+ public final File file;
+
+ public HardLockPath(File file) {
+ this.file = file;
+ }
+
+ }
+
+ /*not private for tests*/
+ public static interface HardLockRegistry {
+ public static HardLockRegistry getInstance() {
+ return HardLockRegistryInstance.INSTANCE;
+ }
+
+ public void doHardLock(HardLockPath hardLock, String absolutePath) throws IOException;
+
+ public boolean doHardUnlock(HardLockPath hardLock);
+
+ public boolean hardLockExists(HardLockPath hardLock) throws IOException;
+
+ public String getHardLockContent(HardLockPath hardLock);
+
+ }
+
+ //init the HardLockRegistry instance lazily:
+ private static final class HardLockRegistryInstance {
+ public static final HardLockRegistry INSTANCE = Lookup.getDefault().lookup(HardLockRegistry.class);
+ }
+
+ @ServiceProvider(service=HardLockRegistry.class, position=100)
+ public static final class FileBaseHardLockRegistry implements HardLockRegistry {
+
+ public void doHardLock(HardLockPath hardLock, String absolutePath) throws IOException {
+ File hardLockFile = hardLock.file;
+ hardLockFile.getParentFile().mkdirs();
+ hardLockFile.createNewFile();
+ try (OutputStream os = Files.newOutputStream(hardLockFile.toPath())) {
+ os.write(absolutePath.getBytes());
+ }
+ }
+
+ public boolean doHardUnlock(HardLockPath hardLock) {
+ return hardLock.file.delete();
+ }
+
+ public boolean hardLockExists(HardLockPath hardLock) throws IOException {
+ return FileChangedManager.getInstance().exists(hardLock.file);
+ }
+
+ public String getHardLockContent(HardLockPath hardLock) {
+ if (FileChangedManager.getInstance().exists(hardLock.file)) {
+ try (InputStream is = new FileInputStream(hardLock.file)) {
+ byte[] path = new byte[is.available()];
+ if (path.length > 0 && is.read(path) == path.length) {
+ return new String(path);
+ }
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+
+ return null;
+ }
+
+ }
+
+ @ServiceProvider(service=HardLockRegistry.class, position=1000)
+ public static final class InMemoryHardLockRegistry implements HardLockRegistry {
+ private final ConcurrentHashMap hardLocks2Content =
+ new ConcurrentHashMap<>();
+
+ private static String getKey(HardLockPath hardLock) throws IOException {
+ Path realParentPath = hardLock.file.toPath().getParent().toRealPath();
+ return realParentPath.resolve(hardLock.file.getName()).toString();
+ }
+
+ public void doHardLock(HardLockPath hardLock, String absolutePath) throws IOException {
+ hardLocks2Content.put(getKey(hardLock), absolutePath);
+ }
+
+ public boolean doHardUnlock(HardLockPath hardLock) {
+ try {
+ return hardLocks2Content.remove(getKey(hardLock)) != null;
+ } catch (IOException ex) {
+ LOGGER.log(Level.FINE, null, ex);
+ return false;
+ }
+ }
+
+ public boolean hardLockExists(HardLockPath hardLock) throws IOException {
+ return hardLocks2Content.containsKey(getKey(hardLock));
+ }
+
+ public String getHardLockContent(HardLockPath hardLock) {
+ try {
+ return hardLocks2Content.get(getKey(hardLock));
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ return null;
+ }
+ }
+
+ }
}
diff --git a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/WriteLockUtils.java b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/WriteLockUtils.java
deleted file mode 100644
index 50c278f091f4..000000000000
--- a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/WriteLockUtils.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.netbeans.modules.masterfs.filebasedfs.fileobjects;
-
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import org.netbeans.modules.masterfs.filebasedfs.utils.FileChangedManager;
-import org.openide.util.Exceptions;
-
-
-/**
- * @author Radek Matous
- */
-
-
-public class WriteLockUtils {
- static final String PREFIX = ".LCK";
- static final String SUFFIX = "~";
-
-
- private WriteLockUtils(){}
-
- public static synchronized boolean hasActiveLockFileSigns(final String filename) {
- return filename.startsWith(WriteLockUtils.PREFIX) && filename.endsWith(WriteLockUtils.SUFFIX);
- }
-
- public static synchronized boolean isActiveLockFile(final File file) {
- final String name = file.getName();
- boolean isActiveLockFile = hasActiveLockFileSigns(name);
- if (isActiveLockFile) {
- final String newName = name.substring(WriteLockUtils.PREFIX.length(), (name.length() - WriteLockUtils.SUFFIX.length()));
- isActiveLockFile = FileChangedManager.getInstance().exists(new File(file.getParentFile(), newName));
- }
-
- return isActiveLockFile;
- }
-
- public static File getAssociatedLockFile(File file) {
- try {
- file = file.getCanonicalFile();
- } catch (IOException iex) {
- Exceptions.printStackTrace(iex);
- }
-
- final File parentFile = file.getParentFile();
- final StringBuilder sb = new StringBuilder();
-
- sb.append(WriteLockUtils.PREFIX);//NOI18N
- sb.append(file.getName());//NOI18N
- sb.append(WriteLockUtils.SUFFIX);//NOI18N
-
- final String lckName = sb.toString();
- final File lck = new File(parentFile, lckName);
- return lck;
- }
-
- static String getContentOfLckFile(File lckFile, FileChannel channel) throws IOException {
- final byte[] readContent = new byte[(int) lckFile.length()];
- channel.read(ByteBuffer.wrap(readContent));
-
- final String retVal = new String(readContent);
- return (FileChangedManager.getInstance().exists(new File(retVal))) ? retVal : null;
- }
-
- static String writeContentOfLckFile(final File lck, FileChannel channel) throws IOException {
- final String absolutePath = lck.getAbsolutePath();
- final ByteBuffer buf = ByteBuffer.wrap(absolutePath.getBytes());
- channel.write(buf);
- return absolutePath;
- }
-}
diff --git a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/utils/FileInfo.java b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/utils/FileInfo.java
index 3ea439d51f2f..09ae48970cc4 100644
--- a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/utils/FileInfo.java
+++ b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/utils/FileInfo.java
@@ -22,7 +22,7 @@
import java.io.File;
import java.io.IOException;
import javax.swing.filechooser.FileSystemView;
-import org.netbeans.modules.masterfs.filebasedfs.fileobjects.WriteLockUtils;
+import org.netbeans.modules.masterfs.filebasedfs.fileobjects.LockForFile;
import org.netbeans.modules.masterfs.filebasedfs.naming.FileNaming;
import org.netbeans.modules.masterfs.filebasedfs.naming.NamingFactory;
import org.openide.filesystems.FileObject;
@@ -153,7 +153,7 @@ public boolean isConvertibleToFileObject() {
public boolean isSupportedFile() {
return (!getFile().getName().equals(".nbattrs") &&
- !WriteLockUtils.hasActiveLockFileSigns(getFile().getName()));
+ !LockForFile.hasActiveLockFileSigns(getFile().getName()));
}
public FileInfo getRoot() {
diff --git a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/BaseFileObjectTestHid.java b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/BaseFileObjectTestHid.java
index 4362868d54f4..d9bde82ffdc4 100644
--- a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/BaseFileObjectTestHid.java
+++ b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/BaseFileObjectTestHid.java
@@ -41,7 +41,7 @@
import org.netbeans.junit.RandomlyFails;
import org.netbeans.modules.masterfs.filebasedfs.fileobjects.FileObj;
import org.netbeans.modules.masterfs.filebasedfs.fileobjects.FileObjectFactory;
-import org.netbeans.modules.masterfs.filebasedfs.fileobjects.WriteLockUtils;
+import org.netbeans.modules.masterfs.filebasedfs.fileobjects.TestUtils;
import org.openide.filesystems.FileAttributeEvent;
import org.openide.filesystems.FileChangeAdapter;
import org.openide.filesystems.FileChangeListener;
@@ -1264,7 +1264,7 @@ public void testLockFileAfterCrash() throws Exception {
File testFile = FileUtil.toFile(testFo);
- File lockFile = WriteLockUtils.getAssociatedLockFile(testFile);
+ File lockFile = TestUtils.getAssociatedLockFile(testFile);
if (!lockFile.exists()) {
assertTrue(lockFile.createNewFile());
}
diff --git a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FolderObjTest.java b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FolderObjTest.java
index 872e334c1e9c..056085f868d1 100644
--- a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FolderObjTest.java
+++ b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FolderObjTest.java
@@ -457,7 +457,7 @@ public void testCreateWriteLock() throws IOException {
final FileObject testRoot = FileBasedFileSystem.getFileObject(getWorkDir());
assertNotNull(testRoot);
File file2lock = new File(getWorkDir(),"aa.txt");
- File associatedLock = WriteLockUtils.getAssociatedLockFile(file2lock);//NOI18N
+ File associatedLock = TestUtils.getAssociatedLockFile(file2lock);//NOI18N
try {
testRoot.createData(associatedLock.getName());
diff --git a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileInMemoryTest.java b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileInMemoryTest.java
new file mode 100644
index 000000000000..e3b5d9a53f65
--- /dev/null
+++ b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileInMemoryTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.netbeans.modules.masterfs.filebasedfs.fileobjects;
+
+import org.netbeans.modules.masterfs.filebasedfs.fileobjects.LockForFile.HardLockRegistry;
+import org.netbeans.modules.masterfs.filebasedfs.fileobjects.LockForFile.InMemoryHardLockRegistry;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+import org.openide.util.lookup.ProxyLookup;
+
+public class LockForFileInMemoryTest extends LockForFileTest {
+
+ public LockForFileInMemoryTest(String testName) {
+ super(testName);
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ Throwable[] exc = new Throwable[1];
+
+ Lookups.executeWith(new ProxyLookup(Lookups.exclude(Lookup.getDefault(), HardLockRegistry.class), Lookups.fixed(new InMemoryHardLockRegistry())), () -> {
+ try {
+ super.runTest();
+ } catch (Throwable t) {
+ exc[0] = t;
+ }
+ });
+
+ if (exc[0] != null) {
+ throw exc[0];
+ }
+ }
+
+}
diff --git a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileTest.java b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileTest.java
index e694f1787fab..f05dc0c50891 100644
--- a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileTest.java
+++ b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileTest.java
@@ -28,6 +28,8 @@
import org.netbeans.junit.NbTestCase;
import org.netbeans.junit.RandomlyFails;
import org.netbeans.modules.masterfs.filebasedfs.FileBasedFileSystem;
+import org.netbeans.modules.masterfs.filebasedfs.fileobjects.LockForFile.HardLockPath;
+import org.netbeans.modules.masterfs.filebasedfs.fileobjects.LockForFile.HardLockRegistry;
import org.openide.filesystems.FileLock;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
@@ -181,16 +183,13 @@ public void testAfterCrashImpl() throws Exception {
LockForFile lock = LockForFile.tryLock(testFile);
lock.releaseLock();
assertFalse(lock.isValid());
- File lockFile = lock.getLock();
- if (!lockFile.exists()) {
- assertTrue(lockFile.createNewFile());
- }
- assertTrue(lockFile.exists());
+ HardLockPath hardLock = lock.getLock();
+ HardLockRegistry.getInstance().doHardLock(hardLock, "");
lock = LockForFile.tryLock(testFile);
try {
assertNotNull(lock);
assertTrue(lock.isValid());
- assertTrue(lockFile.exists());
+ assertTrue(HardLockRegistry.getInstance().hardLockExists(hardLock));
} finally {
lock.releaseLock();
}
@@ -216,9 +215,9 @@ public void testFinalizeImpl() throws Exception {
lock.releaseLock();
LOG.info("releaseLock");
- File lockFile = LockForFile.getLockFile(testFile);
- LOG.log(Level.INFO, "Get lock file: {0}", lockFile);
- assertFalse(lockFile.exists());
+ HardLockPath hardLock = LockForFile.getLockFile(testFile);
+ LOG.log(Level.INFO, "Get lock file: {0}", hardLock);
+ assertFalse(HardLockRegistry.getInstance().hardLockExists(hardLock));
LOG.info("OK");
}
@@ -253,9 +252,9 @@ public void testLockingAndReleasingLockAfterRename_82170() throws Exception {
} catch (IOException ex) {
//after rename is still locked and there isn't possible to get other lock
}
- File lockFile = LockForFile.getLockFile(file);
+ HardLockPath hardLock = LockForFile.getLockFile(file);
lockForFile.releaseLock();
- assertFalse(lockFile.exists());//lock file is deleted after releasing lock
+ assertFalse(HardLockRegistry.getInstance().hardLockExists(hardLock));//lock file is deleted after releasing lock
LockForFile.tryLock(file);//there is possible to get lock after releasing lock
}
diff --git a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/StatFilesTest.java b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/StatFilesTest.java
index e24bd3c4bd14..ef91a0e86738 100644
--- a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/StatFilesTest.java
+++ b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/StatFilesTest.java
@@ -61,6 +61,8 @@ protected void setUp() throws java.lang.Exception {
assertTrue(testFile.exists());
//init
+ //make sure Utilities is loaded:
+ Utilities.isUnix();
FileUtil.toFileObject(testFile);
monitor = new StatFiles();
System.setSecurityManager(monitor);
diff --git a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/TestUtils.java b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/TestUtils.java
index 720c93f016fd..899f8efa20f4 100644
--- a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/TestUtils.java
+++ b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/TestUtils.java
@@ -20,6 +20,7 @@
package org.netbeans.modules.masterfs.filebasedfs.fileobjects;
import java.io.File;
+import java.io.IOException;
import java.lang.ref.Reference;
import java.util.ArrayList;
import java.util.List;
@@ -31,6 +32,7 @@
import org.netbeans.modules.masterfs.watcher.Watcher;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileStateInvalidException;
+import org.openide.util.Exceptions;
public class TestUtils {
private static final Logger LOG = Logger.getLogger(TestUtils.class.getName());
@@ -107,4 +109,23 @@ public static Runnable findSlowRefresh(FileObject fo) throws FileStateInvalidExc
Assert.assertFalse("Watcher is really disabled", Watcher.isEnabled());
return rs;
}
+
+ public static File getAssociatedLockFile(File file) {
+ try {
+ file = file.getCanonicalFile();
+ } catch (IOException iex) {
+ Exceptions.printStackTrace(iex);
+ }
+
+ final File parentFile = file.getParentFile();
+ final StringBuilder sb = new StringBuilder();
+
+ sb.append(LockForFile.PREFIX);//NOI18N
+ sb.append(file.getName());//NOI18N
+ sb.append(LockForFile.SUFFIX);//NOI18N
+
+ final String lckName = sb.toString();
+ final File lck = new File(parentFile, lckName);
+ return lck;
+ }
}
From c4bc50d3fa4a498bf0e17651fbfc4bc2988e1fda Mon Sep 17 00:00:00 2001
From: Jan Lahoda
Date: Mon, 19 Oct 2026 12:28:04 +0200
Subject: [PATCH 2/6] Dropping HardLockPath.
---
.../filebasedfs/fileobjects/LockForFile.java | 65 ++++++++-----------
1 file changed, 27 insertions(+), 38 deletions(-)
diff --git a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFile.java b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFile.java
index 60dd31f70444..fedab1a7fc71 100644
--- a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFile.java
+++ b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFile.java
@@ -52,7 +52,7 @@ public class LockForFile extends FileLock {
static final String SUFFIX = "~";
private static final Logger LOGGER = Logger.getLogger(LockForFile.class.getName());
private File file;
- private HardLockPath lock;
+ private File lock;
private boolean valid = false;
static {
@@ -159,7 +159,7 @@ boolean hardLock() throws IOException {
throw new FileAlreadyLockedException(file.getAbsolutePath());
}
- HardLockPath hardLock = getLock();
+ File hardLock = getLock();
HardLockRegistry.getInstance().doHardLock(hardLock, getFile().getAbsolutePath());
@@ -190,7 +190,7 @@ private static synchronized boolean hardUnlockAll() {
return result;
}
- public HardLockPath getLock() {
+ public File getLock() {
return lock;
}
@@ -215,7 +215,7 @@ public void rename() {
}
- public static HardLockPath getLockFile(File file) {
+ public static File getLockFile(File file) {
file = FileUtil.normalizeFile(file);
final File parentFile = file.getParentFile();
@@ -227,7 +227,7 @@ public static HardLockPath getLockFile(File file) {
final String lckName = sb.toString();
final File lck = new File(parentFile, lckName);
- return new HardLockPath(lck.getAbsoluteFile());
+ return lck.getAbsoluteFile();
}
@Override
@@ -288,28 +288,18 @@ public static boolean hasActiveLockFileSigns(final String filename) {
return filename.startsWith(PREFIX) && filename.endsWith(SUFFIX);
}
- public static final class HardLockPath {
- public final File file;
-
- public HardLockPath(File file) {
- this.file = file;
- }
-
- }
-
- /*not private for tests*/
public static interface HardLockRegistry {
public static HardLockRegistry getInstance() {
return HardLockRegistryInstance.INSTANCE;
}
- public void doHardLock(HardLockPath hardLock, String absolutePath) throws IOException;
+ public void doHardLock(File hardLock, String absolutePath) throws IOException;
- public boolean doHardUnlock(HardLockPath hardLock);
+ public boolean doHardUnlock(File hardLock);
- public boolean hardLockExists(HardLockPath hardLock) throws IOException;
+ public boolean hardLockExists(File hardLock) throws IOException;
- public String getHardLockContent(HardLockPath hardLock);
+ public String getHardLockContent(File hardLock);
}
@@ -321,26 +311,25 @@ private static final class HardLockRegistryInstance {
@ServiceProvider(service=HardLockRegistry.class, position=100)
public static final class FileBaseHardLockRegistry implements HardLockRegistry {
- public void doHardLock(HardLockPath hardLock, String absolutePath) throws IOException {
- File hardLockFile = hardLock.file;
- hardLockFile.getParentFile().mkdirs();
- hardLockFile.createNewFile();
- try (OutputStream os = Files.newOutputStream(hardLockFile.toPath())) {
+ public void doHardLock(File hardLock, String absolutePath) throws IOException {
+ hardLock.getParentFile().mkdirs();
+ hardLock.createNewFile();
+ try (OutputStream os = Files.newOutputStream(hardLock.toPath())) {
os.write(absolutePath.getBytes());
}
}
- public boolean doHardUnlock(HardLockPath hardLock) {
- return hardLock.file.delete();
+ public boolean doHardUnlock(File hardLock) {
+ return hardLock.delete();
}
- public boolean hardLockExists(HardLockPath hardLock) throws IOException {
- return FileChangedManager.getInstance().exists(hardLock.file);
+ public boolean hardLockExists(File hardLock) throws IOException {
+ return FileChangedManager.getInstance().exists(hardLock);
}
- public String getHardLockContent(HardLockPath hardLock) {
- if (FileChangedManager.getInstance().exists(hardLock.file)) {
- try (InputStream is = new FileInputStream(hardLock.file)) {
+ public String getHardLockContent(File hardLock) {
+ if (FileChangedManager.getInstance().exists(hardLock)) {
+ try (InputStream is = new FileInputStream(hardLock)) {
byte[] path = new byte[is.available()];
if (path.length > 0 && is.read(path) == path.length) {
return new String(path);
@@ -360,16 +349,16 @@ public static final class InMemoryHardLockRegistry implements HardLockRegistry {
private final ConcurrentHashMap hardLocks2Content =
new ConcurrentHashMap<>();
- private static String getKey(HardLockPath hardLock) throws IOException {
- Path realParentPath = hardLock.file.toPath().getParent().toRealPath();
- return realParentPath.resolve(hardLock.file.getName()).toString();
+ private static String getKey(File hardLock) throws IOException {
+ Path realParentPath = hardLock.toPath().getParent().toRealPath();
+ return realParentPath.resolve(hardLock.getName()).toString();
}
- public void doHardLock(HardLockPath hardLock, String absolutePath) throws IOException {
+ public void doHardLock(File hardLock, String absolutePath) throws IOException {
hardLocks2Content.put(getKey(hardLock), absolutePath);
}
- public boolean doHardUnlock(HardLockPath hardLock) {
+ public boolean doHardUnlock(File hardLock) {
try {
return hardLocks2Content.remove(getKey(hardLock)) != null;
} catch (IOException ex) {
@@ -378,11 +367,11 @@ public boolean doHardUnlock(HardLockPath hardLock) {
}
}
- public boolean hardLockExists(HardLockPath hardLock) throws IOException {
+ public boolean hardLockExists(File hardLock) throws IOException {
return hardLocks2Content.containsKey(getKey(hardLock));
}
- public String getHardLockContent(HardLockPath hardLock) {
+ public String getHardLockContent(File hardLock) {
try {
return hardLocks2Content.get(getKey(hardLock));
} catch (IOException ex) {
From 35e42448ad0a0cadcaa5e8b8c7fb1439f3c80332 Mon Sep 17 00:00:00 2001
From: Jan Lahoda
Date: Mon, 19 Oct 2026 13:08:14 +0200
Subject: [PATCH 3/6] Putting the classes to the package level.
---
.../fileobjects/FileBaseHardLockRegistry.java | 64 +++++++++++
.../fileobjects/HardLockRegistry.java | 46 ++++++++
.../fileobjects/InMemoryHardLockRegistry.java | 67 +++++++++++
.../filebasedfs/fileobjects/LockForFile.java | 104 ------------------
.../fileobjects/LockForFileInMemoryTest.java | 4 +-
.../fileobjects/LockForFileTest.java | 9 +-
6 files changed, 183 insertions(+), 111 deletions(-)
create mode 100644 platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FileBaseHardLockRegistry.java
create mode 100644 platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/HardLockRegistry.java
create mode 100644 platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/InMemoryHardLockRegistry.java
diff --git a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FileBaseHardLockRegistry.java b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FileBaseHardLockRegistry.java
new file mode 100644
index 000000000000..573ecd8df211
--- /dev/null
+++ b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FileBaseHardLockRegistry.java
@@ -0,0 +1,64 @@
+/*
+ * 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.netbeans.modules.masterfs.filebasedfs.fileobjects;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import org.netbeans.modules.masterfs.filebasedfs.utils.FileChangedManager;
+import org.openide.util.Exceptions;
+import org.openide.util.lookup.ServiceProvider;
+
+@ServiceProvider(service = HardLockRegistry.class, position = 100)
+public final class FileBaseHardLockRegistry implements HardLockRegistry {
+
+ public void doHardLock(File hardLock, String absolutePath) throws IOException {
+ hardLock.getParentFile().mkdirs();
+ hardLock.createNewFile();
+ try (OutputStream os = Files.newOutputStream(hardLock.toPath())) {
+ os.write(absolutePath.getBytes());
+ }
+ }
+
+ public boolean doHardUnlock(File hardLock) {
+ return hardLock.delete();
+ }
+
+ public boolean hardLockExists(File hardLock) throws IOException {
+ return FileChangedManager.getInstance().exists(hardLock);
+ }
+
+ public String getHardLockContent(File hardLock) {
+ if (FileChangedManager.getInstance().exists(hardLock)) {
+ try (InputStream is = new FileInputStream(hardLock)) {
+ byte[] path = new byte[is.available()];
+ if (path.length > 0 && is.read(path) == path.length) {
+ return new String(path);
+ }
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/HardLockRegistry.java b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/HardLockRegistry.java
new file mode 100644
index 000000000000..8512b67b3374
--- /dev/null
+++ b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/HardLockRegistry.java
@@ -0,0 +1,46 @@
+/*
+ * 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.netbeans.modules.masterfs.filebasedfs.fileobjects;
+
+import java.io.File;
+import java.io.IOException;
+import org.openide.util.Lookup;
+
+/** A pluggable hard lock handler. */
+public interface HardLockRegistry {
+
+ public static HardLockRegistry getInstance() {
+ return HardLockRegistryInstance.INSTANCE;
+ }
+
+ public void doHardLock(File hardLock, String absolutePath) throws IOException;
+
+ public boolean doHardUnlock(File hardLock);
+
+ public boolean hardLockExists(File hardLock) throws IOException;
+
+ public String getHardLockContent(File hardLock);
+
+}
+
+//init the HardLockRegistry instance lazily:
+final class HardLockRegistryInstance {
+ public static final HardLockRegistry INSTANCE = Lookup.getDefault().lookup(HardLockRegistry.class);
+}
+
diff --git a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/InMemoryHardLockRegistry.java b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/InMemoryHardLockRegistry.java
new file mode 100644
index 000000000000..2dbfcd2d44d6
--- /dev/null
+++ b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/InMemoryHardLockRegistry.java
@@ -0,0 +1,67 @@
+/*
+ * 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.netbeans.modules.masterfs.filebasedfs.fileobjects;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.openide.util.Exceptions;
+import org.openide.util.lookup.ServiceProvider;
+
+@ServiceProvider(service = HardLockRegistry.class, position = 1000)
+public final class InMemoryHardLockRegistry implements HardLockRegistry {
+
+ private static final Logger LOGGER = Logger.getLogger(InMemoryHardLockRegistry.class.getName());
+ private final ConcurrentHashMap hardLocks2Content = new ConcurrentHashMap<>();
+
+ private static String getKey(File hardLock) throws IOException {
+ Path realParentPath = hardLock.toPath().getParent().toRealPath();
+ return realParentPath.resolve(hardLock.getName()).toString();
+ }
+
+ public void doHardLock(File hardLock, String absolutePath) throws IOException {
+ hardLocks2Content.put(getKey(hardLock), absolutePath);
+ }
+
+ public boolean doHardUnlock(File hardLock) {
+ try {
+ return hardLocks2Content.remove(getKey(hardLock)) != null;
+ } catch (IOException ex) {
+ LOGGER.log(Level.FINE, null, ex);
+ return false;
+ }
+ }
+
+ public boolean hardLockExists(File hardLock) throws IOException {
+ return hardLocks2Content.containsKey(getKey(hardLock));
+ }
+
+ public String getHardLockContent(File hardLock) {
+ try {
+ return hardLocks2Content.get(getKey(hardLock));
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ return null;
+ }
+ }
+
+}
diff --git a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFile.java b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFile.java
index fedab1a7fc71..f96d94cd07a2 100644
--- a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFile.java
+++ b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFile.java
@@ -19,27 +19,17 @@
package org.netbeans.modules.masterfs.filebasedfs.fileobjects;
import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
-import java.nio.file.Files;
-import java.nio.file.Path;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import org.netbeans.modules.masterfs.filebasedfs.utils.FileChangedManager;
import org.netbeans.modules.masterfs.filebasedfs.utils.Utils;
import org.openide.filesystems.FileAlreadyLockedException;
import org.openide.filesystems.FileLock;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.Exceptions;
-import org.openide.util.Lookup;
-import org.openide.util.lookup.ServiceProvider;
/**
* FileLock with support for fine grained hard locking to ensure better performance
@@ -50,7 +40,6 @@ public class LockForFile extends FileLock {
private static final ConcurrentHashMap name2Namesakes = new ConcurrentHashMap<>();
static final String PREFIX = ".LCK";
static final String SUFFIX = "~";
- private static final Logger LOGGER = Logger.getLogger(LockForFile.class.getName());
private File file;
private File lock;
private boolean valid = false;
@@ -288,97 +277,4 @@ public static boolean hasActiveLockFileSigns(final String filename) {
return filename.startsWith(PREFIX) && filename.endsWith(SUFFIX);
}
- public static interface HardLockRegistry {
- public static HardLockRegistry getInstance() {
- return HardLockRegistryInstance.INSTANCE;
- }
-
- public void doHardLock(File hardLock, String absolutePath) throws IOException;
-
- public boolean doHardUnlock(File hardLock);
-
- public boolean hardLockExists(File hardLock) throws IOException;
-
- public String getHardLockContent(File hardLock);
-
- }
-
- //init the HardLockRegistry instance lazily:
- private static final class HardLockRegistryInstance {
- public static final HardLockRegistry INSTANCE = Lookup.getDefault().lookup(HardLockRegistry.class);
- }
-
- @ServiceProvider(service=HardLockRegistry.class, position=100)
- public static final class FileBaseHardLockRegistry implements HardLockRegistry {
-
- public void doHardLock(File hardLock, String absolutePath) throws IOException {
- hardLock.getParentFile().mkdirs();
- hardLock.createNewFile();
- try (OutputStream os = Files.newOutputStream(hardLock.toPath())) {
- os.write(absolutePath.getBytes());
- }
- }
-
- public boolean doHardUnlock(File hardLock) {
- return hardLock.delete();
- }
-
- public boolean hardLockExists(File hardLock) throws IOException {
- return FileChangedManager.getInstance().exists(hardLock);
- }
-
- public String getHardLockContent(File hardLock) {
- if (FileChangedManager.getInstance().exists(hardLock)) {
- try (InputStream is = new FileInputStream(hardLock)) {
- byte[] path = new byte[is.available()];
- if (path.length > 0 && is.read(path) == path.length) {
- return new String(path);
- }
- } catch (IOException ex) {
- Exceptions.printStackTrace(ex);
- }
- }
-
- return null;
- }
-
- }
-
- @ServiceProvider(service=HardLockRegistry.class, position=1000)
- public static final class InMemoryHardLockRegistry implements HardLockRegistry {
- private final ConcurrentHashMap hardLocks2Content =
- new ConcurrentHashMap<>();
-
- private static String getKey(File hardLock) throws IOException {
- Path realParentPath = hardLock.toPath().getParent().toRealPath();
- return realParentPath.resolve(hardLock.getName()).toString();
- }
-
- public void doHardLock(File hardLock, String absolutePath) throws IOException {
- hardLocks2Content.put(getKey(hardLock), absolutePath);
- }
-
- public boolean doHardUnlock(File hardLock) {
- try {
- return hardLocks2Content.remove(getKey(hardLock)) != null;
- } catch (IOException ex) {
- LOGGER.log(Level.FINE, null, ex);
- return false;
- }
- }
-
- public boolean hardLockExists(File hardLock) throws IOException {
- return hardLocks2Content.containsKey(getKey(hardLock));
- }
-
- public String getHardLockContent(File hardLock) {
- try {
- return hardLocks2Content.get(getKey(hardLock));
- } catch (IOException ex) {
- Exceptions.printStackTrace(ex);
- return null;
- }
- }
-
- }
}
diff --git a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileInMemoryTest.java b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileInMemoryTest.java
index e3b5d9a53f65..e99e9c57edbb 100644
--- a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileInMemoryTest.java
+++ b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileInMemoryTest.java
@@ -18,8 +18,8 @@
*/
package org.netbeans.modules.masterfs.filebasedfs.fileobjects;
-import org.netbeans.modules.masterfs.filebasedfs.fileobjects.LockForFile.HardLockRegistry;
-import org.netbeans.modules.masterfs.filebasedfs.fileobjects.LockForFile.InMemoryHardLockRegistry;
+import org.netbeans.modules.masterfs.filebasedfs.fileobjects.HardLockRegistry;
+import org.netbeans.modules.masterfs.filebasedfs.fileobjects.InMemoryHardLockRegistry;
import org.openide.util.Lookup;
import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ProxyLookup;
diff --git a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileTest.java b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileTest.java
index f05dc0c50891..ddbebca518e4 100644
--- a/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileTest.java
+++ b/platform/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/LockForFileTest.java
@@ -28,8 +28,7 @@
import org.netbeans.junit.NbTestCase;
import org.netbeans.junit.RandomlyFails;
import org.netbeans.modules.masterfs.filebasedfs.FileBasedFileSystem;
-import org.netbeans.modules.masterfs.filebasedfs.fileobjects.LockForFile.HardLockPath;
-import org.netbeans.modules.masterfs.filebasedfs.fileobjects.LockForFile.HardLockRegistry;
+import org.netbeans.modules.masterfs.filebasedfs.fileobjects.HardLockRegistry;
import org.openide.filesystems.FileLock;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
@@ -183,7 +182,7 @@ public void testAfterCrashImpl() throws Exception {
LockForFile lock = LockForFile.tryLock(testFile);
lock.releaseLock();
assertFalse(lock.isValid());
- HardLockPath hardLock = lock.getLock();
+ File hardLock = lock.getLock();
HardLockRegistry.getInstance().doHardLock(hardLock, "");
lock = LockForFile.tryLock(testFile);
try {
@@ -215,7 +214,7 @@ public void testFinalizeImpl() throws Exception {
lock.releaseLock();
LOG.info("releaseLock");
- HardLockPath hardLock = LockForFile.getLockFile(testFile);
+ File hardLock = LockForFile.getLockFile(testFile);
LOG.log(Level.INFO, "Get lock file: {0}", hardLock);
assertFalse(HardLockRegistry.getInstance().hardLockExists(hardLock));
LOG.info("OK");
@@ -252,7 +251,7 @@ public void testLockingAndReleasingLockAfterRename_82170() throws Exception {
} catch (IOException ex) {
//after rename is still locked and there isn't possible to get other lock
}
- HardLockPath hardLock = LockForFile.getLockFile(file);
+ File hardLock = LockForFile.getLockFile(file);
lockForFile.releaseLock();
assertFalse(HardLockRegistry.getInstance().hardLockExists(hardLock));//lock file is deleted after releasing lock
LockForFile.tryLock(file);//there is possible to get lock after releasing lock
From c05aba58f8fb63326ac4e38b0b38e5f2fdc60fc4 Mon Sep 17 00:00:00 2001
From: Jan Lahoda
Date: Mon, 19 Oct 2026 15:00:24 +0200
Subject: [PATCH 4/6] API description.
---
platform/masterfs/apichanges.xml | 14 +++++++++++++-
platform/masterfs/arch.xml | 7 +++++++
platform/masterfs/nbproject/project.properties | 2 +-
3 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/platform/masterfs/apichanges.xml b/platform/masterfs/apichanges.xml
index 85880c4782c7..aadbc889e177 100644
--- a/platform/masterfs/apichanges.xml
+++ b/platform/masterfs/apichanges.xml
@@ -19,12 +19,24 @@
under the License.
-->
-
+
MasterFileSystem API
+
+
+ Split image handling into UI module
+
+
+
+
+
+ Adding an ability to disable hard-locks using files on the file system.
+
+
+
Split image handling into UI module
diff --git a/platform/masterfs/arch.xml b/platform/masterfs/arch.xml
index 73fc88cadb22..015a84e7fd56 100644
--- a/platform/masterfs/arch.xml
+++ b/platform/masterfs/arch.xml
@@ -112,6 +112,13 @@ cases. FileObjects erlier returned from URLMapper or
CvsFileSystem will be now provided by MasterFileSystem.
There will be guaranteed that there won't be more instances of FileObject
addressing one java.ioFile.
+
+To disable hard locks as on-disk files, remove class org.netbeans.modules.masterfs.filebasedfs.fileobjects.FileBaseHardLockRegistry
+from the global Lookup, e.g. by creating file:
+org.netbeans.modules.masterfs.filebasedfs.fileobjects.HardLockRegistry with this content:
+#-org.netbeans.modules.masterfs.filebasedfs.fileobjects.FileBaseHardLockRegistry.
+This is an API under development and may be replaced or changed in the future.
+
diff --git a/platform/masterfs/nbproject/project.properties b/platform/masterfs/nbproject/project.properties
index 38c951309f1b..55cb283ba746 100644
--- a/platform/masterfs/nbproject/project.properties
+++ b/platform/masterfs/nbproject/project.properties
@@ -35,7 +35,7 @@ test.config.stableBTD.excludes=\
**/SlowRefreshAndPriorityIOTest.class,\
**/SlowRefreshSuspendableTest.class,\
**/StatFilesTest.class
-spec.version.base=2.90.0
+spec.version.base=2.91.0
# TODO remove SM usage in tests
test.jms.flags=-Djava.security.manager=allow
From 4d7d058af50b55a8b072661e4394f2763a2d4829 Mon Sep 17 00:00:00 2001
From: Jan Lahoda
Date: Mon, 19 Oct 2026 17:42:17 +0200
Subject: [PATCH 5/6] Improving wording.
---
platform/masterfs/arch.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/platform/masterfs/arch.xml b/platform/masterfs/arch.xml
index 015a84e7fd56..e991a81d6664 100644
--- a/platform/masterfs/arch.xml
+++ b/platform/masterfs/arch.xml
@@ -115,7 +115,7 @@ addressing one java.ioFile.
To disable hard locks as on-disk files, remove class org.netbeans.modules.masterfs.filebasedfs.fileobjects.FileBaseHardLockRegistry
from the global Lookup, e.g. by creating file:
-org.netbeans.modules.masterfs.filebasedfs.fileobjects.HardLockRegistry with this content:
+META-INF/services/org.netbeans.modules.masterfs.filebasedfs.fileobjects.HardLockRegistry with this content:
#-org.netbeans.modules.masterfs.filebasedfs.fileobjects.FileBaseHardLockRegistry.
This is an API under development and may be replaced or changed in the future.
From c4d033c047de9ca8e1975858be9faca2a4104975 Mon Sep 17 00:00:00 2001
From: Jan Lahoda
Date: Thu, 22 Oct 2026 14:48:25 +0200
Subject: [PATCH 6/6] Adding api usecase links as suggested.
---
platform/masterfs/apichanges.xml | 3 ++-
platform/masterfs/arch.xml | 4 ++--
.../masterfs/filebasedfs/fileobjects/HardLockRegistry.java | 4 +++-
3 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/platform/masterfs/apichanges.xml b/platform/masterfs/apichanges.xml
index aadbc889e177..31cc03064ce1 100644
--- a/platform/masterfs/apichanges.xml
+++ b/platform/masterfs/apichanges.xml
@@ -27,13 +27,14 @@
- Split image handling into UI module
+ Adding ability to disable hard-locks as files
Adding an ability to disable hard-locks using files on the file system.
+ See the API usecase.
diff --git a/platform/masterfs/arch.xml b/platform/masterfs/arch.xml
index e991a81d6664..d78bc163c78b 100644
--- a/platform/masterfs/arch.xml
+++ b/platform/masterfs/arch.xml
@@ -112,13 +112,13 @@ cases. FileObjects erlier returned from URLMapper or
CvsFileSystem will be now provided by MasterFileSystem.
There will be guaranteed that there won't be more instances of FileObject
addressing one java.ioFile.
-
+
To disable hard locks as on-disk files, remove class org.netbeans.modules.masterfs.filebasedfs.fileobjects.FileBaseHardLockRegistry
from the global Lookup, e.g. by creating file:
META-INF/services/org.netbeans.modules.masterfs.filebasedfs.fileobjects.HardLockRegistry with this content:
#-org.netbeans.modules.masterfs.filebasedfs.fileobjects.FileBaseHardLockRegistry.
This is an API under development and may be replaced or changed in the future.
-
+
diff --git a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/HardLockRegistry.java b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/HardLockRegistry.java
index 8512b67b3374..b1994a52cb09 100644
--- a/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/HardLockRegistry.java
+++ b/platform/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/HardLockRegistry.java
@@ -22,7 +22,9 @@
import java.io.IOException;
import org.openide.util.Lookup;
-/** A pluggable hard lock handler. */
+/** A pluggable hard lock handler.
+ * @see the API usecase..
+ */
public interface HardLockRegistry {
public static HardLockRegistry getInstance() {