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() {