X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.acorn%2Fsrc%2Forg%2Fsimantics%2Facorn%2Finternal%2FAcornDatabase.java;h=db83f1395d005babeb09dbd500f5034d2326f503;hb=refs%2Fchanges%2F95%2F495%2F1;hp=63c73dd634580e2c3f1add6c4d34b6d866ff926f;hpb=8ada31c956ee02aef38627ba4deaaae3eecb623a;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.acorn/src/org/simantics/acorn/internal/AcornDatabase.java b/bundles/org.simantics.acorn/src/org/simantics/acorn/internal/AcornDatabase.java index 63c73dd63..db83f1395 100644 --- a/bundles/org.simantics.acorn/src/org/simantics/acorn/internal/AcornDatabase.java +++ b/bundles/org.simantics.acorn/src/org/simantics/acorn/internal/AcornDatabase.java @@ -2,12 +2,16 @@ package org.simantics.acorn.internal; import java.io.File; import java.io.IOException; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; import java.nio.file.DirectoryStream; +import java.nio.file.FileAlreadyExistsException; import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardOpenOption; import java.nio.file.attribute.BasicFileAttributes; import java.util.EnumSet; import java.util.Properties; @@ -16,20 +20,36 @@ import org.simantics.acorn.GraphClientImpl2; import org.simantics.db.Database; import org.simantics.db.DatabaseUserAgent; import org.simantics.db.ServiceLocator; -import org.simantics.db.common.utils.Logger; +import org.simantics.db.server.DatabaseStartException; import org.simantics.db.server.ProCoreException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author Tuukka Lehtonen */ public class AcornDatabase implements Database { + private static final Logger LOGGER = LoggerFactory.getLogger(AcornDatabase.class); + + private static final String LOCK_FILE_NAME = "lock"; + private final Path folder; + private final Path lockFile; + + private GraphClientImpl2 currentClient; private DatabaseUserAgent userAgent; + private FileChannel lockFileChannel; + + private FileLock lock; + + private boolean isRunning; + public AcornDatabase(Path folder) { this.folder = folder; + this.lockFile = folder.resolve(LOCK_FILE_NAME); } @Override @@ -77,7 +97,7 @@ public class AcornDatabase implements Database { try (DirectoryStream folderStream = Files.newDirectoryStream(path)) { return !folderStream.iterator().hasNext(); } catch (IOException e) { - Logger.defaultLogError("Failed to open folder stream. folder=" + path, e); + LOGGER.error("Failed to open folder stream. folder=" + path, e); return false; } } @@ -93,23 +113,48 @@ public class AcornDatabase implements Database { @Override public void deleteFiles() throws ProCoreException { - // TODO: somehow check that the acorn client is not active. deleteTree(folder); } @Override - public void start() throws ProCoreException { + public synchronized void start() throws ProCoreException { + try { + lockFileChannel = lockFile.getFileSystem().provider().newFileChannel(lockFile, + EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE)); + + lock = lockFileChannel.tryLock(); + if (lock == null) { + safeLoggingClose(lockFileChannel, lockFile); + throw new ProCoreException("The database in folder " + folder.toAbsolutePath() + " is already in use!"); + } + + isRunning = true; + } catch (IOException e) { + LOGGER.error("Failed to start database at " + folder.toAbsolutePath(), e); + safeLoggingClose(lockFileChannel, lockFile); + } } @Override public boolean isRunning() throws ProCoreException { - return true; + return isRunning; } @Override - public boolean tryToStop() throws ProCoreException { + public synchronized boolean tryToStop() throws ProCoreException { + if (!isRunning) + return false; + try { + safeLoggingClose(lock, lockFile); + lock = null; + safeLoggingClose(lockFileChannel, lockFile); + lockFileChannel = null; + Files.deleteIfExists(lockFile); + isRunning = false; + } catch (IOException e) { + LOGGER.error("Failed to start database at " + folder.toAbsolutePath(), e); + } return true; -// throw new UnsupportedOperationException(); } @Override @@ -118,7 +163,7 @@ public class AcornDatabase implements Database { @Override public boolean isConnected() throws ProCoreException { - return true; + return isRunning; } @Override @@ -156,22 +201,22 @@ public class AcornDatabase implements Database { @Override public void purgeDatabase() throws ProCoreException { - // TODO: implement - throw new UnsupportedOperationException(); + if(currentClient == null) throw new IllegalStateException("No current session."); + currentClient.purgeDatabase(); } @Override public long serverGetTailChangeSetId() throws ProCoreException { - // "We have it all" - // But after purging we don't so beware. - // TODO: beware for purge - return 1; + if(currentClient == null) throw new IllegalStateException("No current session."); + return currentClient.getTailChangeSetId(); } @Override public Session newSession(ServiceLocator locator) throws ProCoreException { try { - return new GraphClientImpl2(this, folder, locator); + if(currentClient != null) throw new DatabaseStartException(folder.toFile(), "A session is already running. Only one session is supported."); + currentClient = new GraphClientImpl2(this, folder, locator); + return currentClient; } catch (IOException e) { throw new ProCoreException(e); } @@ -226,4 +271,13 @@ public class AcornDatabase implements Database { return "LZ4"; } + private static void safeLoggingClose(AutoCloseable closeable, Path file) { + if (closeable == null) + return; + try (AutoCloseable c = closeable) { + } catch (Exception e) { + LOGGER.error("Failed to close " + closeable.getClass() + " of " + file.toAbsolutePath()); + } + } + }