Some Acorn improvements 48/48/3
authorjsimomaa <jani.simomaa@gmail.com>
Mon, 5 Sep 2016 12:28:00 +0000 (15:28 +0300)
committerjsimomaa <jani.simomaa@gmail.com>
Mon, 5 Sep 2016 12:46:12 +0000 (15:46 +0300)
1) Acorn: do not make snapshot if cancelCommit() is called

In some situations it is possible that when cancelCommit() is called
that acorn head.state writing writes nonsense due to
IllegalStateException being thrown from LRUObject.getStateKey()

2) Acorn: use a lock file to lock the current database

Use a lock file to prevent simultaneous usages of same database in Acorn

refs #6596

Change-Id: Ia33b90f85371c48154763f8a603cdce9a61d9ed6

bundles/org.simantics.acorn/src/org/simantics/acorn/AcornDriver.java
bundles/org.simantics.acorn/src/org/simantics/acorn/AcornManagement.java
bundles/org.simantics.acorn/src/org/simantics/acorn/GraphClientImpl2.java
bundles/org.simantics.acorn/src/org/simantics/acorn/internal/AcornDatabase.java

index 0e6d52b9abf0ef3f6912951424207f363bd38895..99ec490621edb30449380b7bf42e909fe90da7a9 100644 (file)
@@ -65,38 +65,7 @@ public class AcornDriver implements Driver {
 
     @Override
     public ServerI getServer(String address, Properties properties) throws DatabaseException {
-        return new ServerI() {
-            
-            @Override
-            public void stop() throws DatabaseException {
-                // nop
-            }
-            
-            @Override
-            public void start() throws DatabaseException {
-                // nop
-            }
-            
-            @Override
-            public boolean isActive() throws DatabaseException {
-                return true;
-            }
-            
-            @Override
-            public String getAddress() throws DatabaseException {
-                return address;
-            }
-            
-            @Override
-            public String executeAndDisconnect(String command) throws DatabaseException {
-                return "";
-            }
-            
-            @Override
-            public String execute(String command) throws DatabaseException {
-                return "";
-            }
-        };
+        return new AcornServerI(address);
     }
 
     @Override
@@ -104,5 +73,44 @@ public class AcornDriver implements Driver {
         Path dbFolder = Paths.get(address);
         return new AcornManagement(dbFolder, properties);
     }
+    
+    private static class AcornServerI implements ServerI {
+        
+        private String address;
+
+        public AcornServerI(String address) {
+            this.address = address;
+        }
+        
+        @Override
+        public void stop() throws DatabaseException {
+            AcornDatabaseManager.getDatabase(Paths.get(address)).tryToStop();
+        }
+        
+        @Override
+        public void start() throws DatabaseException {
+            AcornDatabaseManager.getDatabase(Paths.get(address)).start();
+        }
+        
+        @Override
+        public boolean isActive() throws DatabaseException {
+            return AcornDatabaseManager.getDatabase(Paths.get(address)).isRunning();
+        }
+        
+        @Override
+        public String getAddress() throws DatabaseException {
+            return address;
+        }
+        
+        @Override
+        public String executeAndDisconnect(String command) throws DatabaseException {
+            return "";
+        }
+        
+        @Override
+        public String execute(String command) throws DatabaseException {
+            return "";
+        }
+    }
 
 }
index 561a039134d8e80b69ce47c4f78c5ffc0a02ac45..a7bccf087a37ddf7d6d59b26ced96c97702e37b6 100644 (file)
@@ -34,7 +34,7 @@ public class AcornManagement implements Management {
     public void create() throws DatabaseException {
         db.initFolder(properties);
         if (!exist())
-            throw new DatabaseException("Failed to create ProCore database. folder=" + db.getFolder());
+            throw new DatabaseException("Failed to create Acorn database. folder=" + db.getFolder());
     }
 
     @Override
index 2796e3e02e32ce514a7d7226c4e029708bcf24b0..774b605541371766333fa19957e57171bc40fdab 100644 (file)
@@ -140,7 +140,8 @@ public class GraphClientImpl2 implements Database.Session {
        }
        
     public void makeSnapshot(boolean force) throws IOException {
-        clusters.makeSnapshot(locator, force);
+        if (safeToMakeSnapshot)
+            clusters.makeSnapshot(locator, force);
     }
        
        public <T> T clone(ClusterUID uid, ClusterCreator creator) throws DatabaseException {
@@ -166,6 +167,8 @@ public class GraphClientImpl2 implements Database.Session {
 
        private boolean closed = false;
        private boolean isClosing = false;
+       // Add check to make sure if it safe to make snapshot (used with cancel which is not yet supported and may cause corrupted head.state writing)
+    private boolean safeToMakeSnapshot = true;
        
        @Override
        public void close() throws ProCoreException {
@@ -173,7 +176,7 @@ public class GraphClientImpl2 implements Database.Session {
                if(!closed && !isClosing) {
                    isClosing = true;
                        try {
-                               makeSnapshot(true);
+                           makeSnapshot(true);
                                
                                mainProgram.close();
                                clusters.shutdown();
@@ -228,15 +231,17 @@ public class GraphClientImpl2 implements Database.Session {
        public long cancelCommit(long transactionId, long changeSetId,
                        byte[] metadata, OnChangeSetUpdate onChangeSetUpdate)
                        throws ProCoreException {
-           System.err.println("GraphClientImpl2.cancelCommit() called!! this is experimental and might cause havoc!");
-           try {
-            undo(new long[] {changeSetId}, onChangeSetUpdate);
-        } catch (SDBException e) {
-            e.printStackTrace();
-            throw new ProCoreException(e);
-        }
-           clusters.state.headChangeSetId++;
-           return clusters.state.headChangeSetId;
+           safeToMakeSnapshot = false;
+           throw new UnsupportedOperationException("org.simantics.acorn.GraphClientImpl2.cancelCommit() is not supported operation! Closing down to prevent further havoc");
+//         System.err.println("GraphClientImpl2.cancelCommit() called!! this is experimental and might cause havoc!");
+//         try {
+//            undo(new long[] {changeSetId}, onChangeSetUpdate);
+//        } catch (SDBException e) {
+//            e.printStackTrace();
+//            throw new ProCoreException(e);
+//        }
+//         clusters.state.headChangeSetId++;
+//         return clusters.state.headChangeSetId;
        }
 
        @Override
index 63c73dd634580e2c3f1add6c4d34b6d866ff926f..be505c6039712e322ce80ffa653c1b4c6babac13 100644 (file)
@@ -2,6 +2,8 @@ package org.simantics.acorn.internal;
 
 import java.io.File;
 import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileLock;
 import java.nio.file.DirectoryStream;
 import java.nio.file.FileVisitOption;
 import java.nio.file.FileVisitResult;
@@ -28,6 +30,12 @@ public class AcornDatabase implements Database {
 
     private DatabaseUserAgent userAgent;
 
+    private RandomAccessFile raLockFile;
+
+    private FileLock lock;
+
+    private boolean isRunning;
+
     public AcornDatabase(Path folder) {
         this.folder = folder;
     }
@@ -93,23 +101,49 @@ 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 {
+        Path lockFile = folder.resolve("lock");
+        try {
+            if (!Files.exists(lockFile))
+                Files.createFile(lockFile);
+            
+            raLockFile = new RandomAccessFile(lockFile.toFile(), "rw");
+            lock = raLockFile.getChannel().tryLock();
+            if (lock == null) {
+                throw new ProCoreException("The database in folder " + folder.toAbsolutePath() + " is already in use!");
+            }
+            
+            isRunning = true;
+            
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
     }
 
     @Override
     public boolean isRunning() throws ProCoreException {
-        return true;
+        return isRunning;
     }
 
     @Override
     public boolean tryToStop() throws ProCoreException {
+        try {
+            lock.release();
+            raLockFile.close();
+            
+            Files.deleteIfExists(folder.resolve("lock"));
+            
+            isRunning = false;
+            
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        
         return true;
-//        throw new UnsupportedOperationException();
     }
 
     @Override
@@ -118,7 +152,7 @@ public class AcornDatabase implements Database {
 
     @Override
     public boolean isConnected() throws ProCoreException {
-        return true;
+        return isRunning;
     }
 
     @Override