]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Acorn: Fix WriteRunnable.runReally() and other fixes 07/107/2
authorjsimomaa <jani.simomaa@gmail.com>
Tue, 27 Sep 2016 11:59:56 +0000 (14:59 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Tue, 27 Sep 2016 12:10:17 +0000 (15:10 +0300)
Lets hope this crlf thing is over after this

refs #6709

Change-Id: I4e69d8eebf790c2bf4352c1bc8130ba62f126d2f

32 files changed:
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/AcornSessionManagerImpl.java
bundles/org.simantics.acorn/src/org/simantics/acorn/ClusterManager.java
bundles/org.simantics.acorn/src/org/simantics/acorn/FileIO.java
bundles/org.simantics.acorn/src/org/simantics/acorn/GraphClientImpl2.java
bundles/org.simantics.acorn/src/org/simantics/acorn/HeadState.java
bundles/org.simantics.acorn/src/org/simantics/acorn/MainProgram.java
bundles/org.simantics.acorn/src/org/simantics/acorn/MainState.java
bundles/org.simantics.acorn/src/org/simantics/acorn/Persistable.java
bundles/org.simantics.acorn/src/org/simantics/acorn/backup/AcornBackupProvider.java
bundles/org.simantics.acorn/src/org/simantics/acorn/cluster/ClusterBig.java
bundles/org.simantics.acorn/src/org/simantics/acorn/cluster/ClusterSmall.java
bundles/org.simantics.acorn/src/org/simantics/acorn/exception/AcornAccessVerificationException.java [new file with mode: 0644]
bundles/org.simantics.acorn/src/org/simantics/acorn/exception/IllegalAcornStateException.java [new file with mode: 0644]
bundles/org.simantics.acorn/src/org/simantics/acorn/exception/InvalidHeadStateException.java [moved from bundles/org.simantics.acorn/src/org/simantics/acorn/InvalidHeadStateException.java with 94% similarity]
bundles/org.simantics.acorn/src/org/simantics/acorn/internal/ClusterSupport2.java
bundles/org.simantics.acorn/src/org/simantics/acorn/internal/ClusterUpdateProcessor.java
bundles/org.simantics.acorn/src/org/simantics/acorn/internal/ClusterUpdateProcessor2.java
bundles/org.simantics.acorn/src/org/simantics/acorn/internal/ClusterUpdateProcessorBase.java
bundles/org.simantics.acorn/src/org/simantics/acorn/internal/ClusterUpdateProcessorBase2.java
bundles/org.simantics.acorn/src/org/simantics/acorn/internal/UndoClusterUpdateProcessor.java
bundles/org.simantics.acorn/src/org/simantics/acorn/lru/ChangeSetInfo.java
bundles/org.simantics.acorn/src/org/simantics/acorn/lru/ClusterChangeSet.java
bundles/org.simantics.acorn/src/org/simantics/acorn/lru/ClusterInfo.java
bundles/org.simantics.acorn/src/org/simantics/acorn/lru/ClusterLRU.java
bundles/org.simantics.acorn/src/org/simantics/acorn/lru/ClusterStreamChunk.java
bundles/org.simantics.acorn/src/org/simantics/acorn/lru/ClusterUpdateOperation.java
bundles/org.simantics.acorn/src/org/simantics/acorn/lru/FileInfo.java
bundles/org.simantics.acorn/src/org/simantics/acorn/lru/LRU.java
bundles/org.simantics.acorn/src/org/simantics/acorn/lru/LRUObject.java
bundles/org.simantics.acorn/src/org/simantics/db/javacore/HeadState.java

index 99ec490621edb30449380b7bf42e909fe90da7a9..536c35c74552b345d73b38a3c68e066212bd9af8 100644 (file)
@@ -2,8 +2,11 @@ package org.simantics.acorn;
 
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Properties;
 
+import org.simantics.db.Database;
 import org.simantics.db.DatabaseUserAgent;
 import org.simantics.db.Driver;
 import org.simantics.db.ServerI;
@@ -16,6 +19,9 @@ public class AcornDriver implements Driver {
 
     public static final String AcornDriverName = "acorn";
 
+    private Map<String, ServerI> servers = new HashMap<>();
+    private Map<String, Management> managements = new HashMap<>();
+    
     @Override
     public String getName() {
         return AcornDriverName;
@@ -23,14 +29,12 @@ public class AcornDriver implements Driver {
 
     @Override
     public DatabaseUserAgent getDatabaseUserAgent(String address) throws DatabaseException {
-        Path dbFolder = Paths.get(address);
-        return AcornDatabaseManager.getDatabase(dbFolder).getUserAgent();
+        return AcornDatabaseManager.getDatabase(Paths.get(address)).getUserAgent();
     }
 
     @Override
     public void setDatabaseUserAgent(String address, DatabaseUserAgent dbUserAgent) throws DatabaseException {
-        Path dbFolder = Paths.get(address);
-        AcornDatabaseManager.getDatabase(dbFolder).setUserAgent(dbUserAgent);
+        AcornDatabaseManager.getDatabase(Paths.get(address)).setUserAgent(dbUserAgent);
     }
 
     @Override
@@ -55,7 +59,7 @@ public class AcornDriver implements Driver {
             }
         }, null);
         if (!properties.containsKey("clientId"))
-            properties.put("clientId", dbFolder.toFile().getAbsolutePath());
+            properties.put("clientId", dbFolder.toAbsolutePath().toString());
         session.registerService(Properties.class, properties);
         Session s = session.peekService(Session.class);
         if (null == s)
@@ -65,36 +69,47 @@ public class AcornDriver implements Driver {
 
     @Override
     public ServerI getServer(String address, Properties properties) throws DatabaseException {
-        return new AcornServerI(address);
+        ServerI server = servers.get(address);
+        if (server == null) {
+            server = new AcornServerI(AcornDatabaseManager.getDatabase(Paths.get(address)), address);
+            servers.put(address, server);
+        }
+        return server;
     }
 
     @Override
     public Management getManagement(String address, Properties properties) throws DatabaseException {
-        Path dbFolder = Paths.get(address);
-        return new AcornManagement(dbFolder, properties);
+        Management mgmt = managements.get(address);
+        if (mgmt == null) {
+            mgmt = new AcornManagement(AcornDatabaseManager.getDatabase(Paths.get(address)), properties);
+            managements.put(address, mgmt);
+        }
+        return mgmt;
     }
     
     private static class AcornServerI implements ServerI {
         
+        private Database database;
         private String address;
 
-        public AcornServerI(String address) {
+        public AcornServerI(Database db, String address) {
+            this.database = db;
             this.address = address;
         }
         
         @Override
         public void stop() throws DatabaseException {
-            AcornDatabaseManager.getDatabase(Paths.get(address)).tryToStop();
+            database.tryToStop();
         }
         
         @Override
         public void start() throws DatabaseException {
-            AcornDatabaseManager.getDatabase(Paths.get(address)).start();
+            database.start();
         }
         
         @Override
         public boolean isActive() throws DatabaseException {
-            return AcornDatabaseManager.getDatabase(Paths.get(address)).isRunning();
+            return database.isRunning();
         }
         
         @Override
index a7bccf087a37ddf7d6d59b26ced96c97702e37b6..c214912108900db80abe0dab11af777af7c2d5fe 100644 (file)
@@ -13,8 +13,8 @@ public class AcornManagement implements Management {
     private final Database db;
     private final Properties properties;
 
-    AcornManagement(Path dbFolder, Properties properties) throws ProCoreException {
-        db = AcornDatabaseManager.getDatabase(dbFolder);
+    AcornManagement(Database db, Properties properties) throws ProCoreException {
+        this.db = db;
         this.properties = properties;
     }
 
index 1a1e16024d859907172baba4bc73bed478699d6b..f67a4aa7c6b702843647467f05a650b41a3aa102 100644 (file)
@@ -13,6 +13,7 @@ import org.simantics.db.common.utils.Logger;
 import org.simantics.db.event.SessionEvent;
 import org.simantics.db.event.SessionListener;
 import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.RuntimeDatabaseException;
 import org.simantics.db.service.LifecycleSupport;
 import org.simantics.utils.datastructures.ListenerList;
 
@@ -23,8 +24,8 @@ public class AcornSessionManagerImpl implements SessionManager {
 
     private static AcornSessionManagerImpl INSTANCE;
     
-    private ConcurrentHashMap<SessionImplSocket, SessionImplSocket> sessionMap = new ConcurrentHashMap<SessionImplSocket, SessionImplSocket>();
-    private ListenerList<SessionListener> sessionListeners = new ListenerList<SessionListener>(SessionListener.class);
+    private ConcurrentHashMap<SessionImplDb, Database.Session> sessionMap = new ConcurrentHashMap<>();
+    private ListenerList<SessionListener> sessionListeners = new ListenerList<>(SessionListener.class);
     private SessionErrorHandler errorHandler;
 
        private Database database;
@@ -51,7 +52,7 @@ public class AcornSessionManagerImpl implements SessionManager {
             database = AcornDatabaseManager.getDatabase(dbFolder);
             Database.Session dbSession = database.newSession(sessionImpl);
             sessionImpl.connect(sessionReference, dbSession);
-            sessionMap.put(sessionImpl, sessionImpl);
+            sessionMap.put(sessionImpl, dbSession);
             fireSessionOpened(sessionImpl);
             ok = true;
         } catch (Throwable e) {
@@ -91,7 +92,7 @@ public class AcornSessionManagerImpl implements SessionManager {
 
     @Override
     public void shutdown(Session s, Throwable cause) {
-        SessionImplSocket sis = sessionMap.get(s);
+        SessionImplSocket sis = (SessionImplSocket) s;
         if (null == sis)
             return;
         try {
@@ -122,4 +123,10 @@ public class AcornSessionManagerImpl implements SessionManager {
         return database;
     }
 
+    public GraphClientImpl2 getClient() {
+        if (sessionMap.values().size() > 1)
+            throw new RuntimeDatabaseException("Currently only one GraphClientImpl2 per session is supported!");
+        org.simantics.db.Database.Session client = sessionMap.values().iterator().next();
+        return (GraphClientImpl2) client;
+    }
 }
index 5b8e5abb8fb8589d08bcd5e0a4b03577e8c078ba..51db52efc55a43108df3939b5bd23561700b6784 100644 (file)
@@ -9,8 +9,12 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.simantics.acorn.cluster.ClusterImpl;
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
+import org.simantics.acorn.exception.InvalidHeadStateException;
 import org.simantics.acorn.internal.ClusterSupport2;
 import org.simantics.acorn.lru.ChangeSetInfo;
 import org.simantics.acorn.lru.ClusterInfo;
@@ -19,15 +23,14 @@ import org.simantics.acorn.lru.ClusterStreamChunk;
 import org.simantics.acorn.lru.FileInfo;
 import org.simantics.acorn.lru.LRU;
 import org.simantics.db.ClusterCreator;
-import org.simantics.db.ServiceLocator;
 import org.simantics.db.Database.Session.ClusterIds;
 import org.simantics.db.Database.Session.ResourceSegment;
+import org.simantics.db.ServiceLocator;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.impl.ClusterBase;
 import org.simantics.db.impl.ClusterI;
 import org.simantics.db.impl.ClusterSupport;
 import org.simantics.db.procore.cluster.ClusterTraits;
-import org.simantics.db.server.ProCoreException;
 import org.simantics.db.service.ClusterSetsSupport;
 import org.simantics.db.service.ClusterUID;
 import org.simantics.utils.threads.logger.ITask;
@@ -62,52 +65,50 @@ public class ClusterManager {
                this.dbFolder = dbFolder;
        }
 
-       public ArrayList<String> getChanges(long changeSetId) {
+       public ArrayList<String> getChanges(long changeSetId) throws AcornAccessVerificationException, IllegalAcornStateException {
                ChangeSetInfo info = csLRU.getWithoutMutex(changeSetId);
                info.acquireMutex();
                try {
                        info.makeResident();
                        return info.getCSSIds();
-               } catch (Throwable t) {
-                       throw new IllegalStateException(t);
                } finally {
                        info.releaseMutex();
                }
        }
 
-       public ClusterBase getClusterByClusterKey(int clusterKey) throws DatabaseException {
+       public ClusterBase getClusterByClusterKey(int clusterKey) throws DatabaseException, AcornAccessVerificationException, IllegalAcornStateException {
                return clusterLRU.getClusterByClusterKey(clusterKey);
        }
        
-       public ClusterBase getClusterByClusterUIDOrMake(ClusterUID clusterUID) throws DatabaseException {
+       public ClusterBase getClusterByClusterUIDOrMake(ClusterUID clusterUID) throws DatabaseException, AcornAccessVerificationException, IllegalAcornStateException {
                return clusterLRU.getClusterByClusterUIDOrMake(clusterUID);
        }
 
-       public ClusterImpl getClusterByClusterUIDOrMakeProxy(ClusterUID clusterUID) throws DatabaseException {
+       public ClusterImpl getClusterByClusterUIDOrMakeProxy(ClusterUID clusterUID) throws DatabaseException, AcornAccessVerificationException, IllegalAcornStateException {
                return clusterLRU.getClusterByClusterUIDOrMakeProxy(clusterUID);
        }
 
-       public int getClusterKeyByClusterUIDOrMake(ClusterUID clusterUID) {
+       public int getClusterKeyByClusterUIDOrMake(ClusterUID clusterUID) throws AcornAccessVerificationException {
                return clusterLRU.getClusterKeyByClusterUIDOrMake(clusterUID);
        }
 
-       public int getClusterKeyByClusterUIDOrMakeWithoutMutex(ClusterUID clusterUID) {
+       public int getClusterKeyByClusterUIDOrMakeWithoutMutex(ClusterUID clusterUID) throws IllegalAcornStateException, AcornAccessVerificationException {
                return clusterLRU.getClusterKeyByClusterUIDOrMakeWithoutMutex(clusterUID);
        }
 
-       public int getClusterKeyByUID(long id1, long id2) throws DatabaseException {
+       public int getClusterKeyByUID(long id1, long id2) throws DatabaseException, IllegalAcornStateException {
                return clusterLRU.getClusterKeyByUIDWithoutMutex(id1, id2);
        }
        
-       public <T extends ClusterI> T getClusterProxyByResourceKey(int resourceKey) throws DatabaseException {
+       public <T extends ClusterI> T getClusterProxyByResourceKey(int resourceKey) throws DatabaseException, AcornAccessVerificationException, IllegalAcornStateException {
                return clusterLRU.getClusterProxyByResourceKey(resourceKey);
        }
 
-       public ClusterUID getClusterUIDByResourceKey(int resourceKey) throws DatabaseException {
+       public ClusterUID getClusterUIDByResourceKey(int resourceKey) throws DatabaseException, AcornAccessVerificationException {
                return clusterLRU.getClusterUIDByResourceKey(resourceKey);
        }
 
-       public ClusterUID getClusterUIDByResourceKeyWithoutMutex(int resourceKey) throws DatabaseException {
+       public ClusterUID getClusterUIDByResourceKeyWithoutMutex(int resourceKey) throws DatabaseException, IllegalAcornStateException, AcornAccessVerificationException {
                return clusterLRU.getClusterUIDByResourceKeyWithoutMutex(resourceKey);
        }
 
@@ -125,69 +126,86 @@ public class ClusterManager {
                }
        }
 
-       public synchronized boolean makeSnapshot(ServiceLocator locator, boolean force) throws IOException {
-
-               // Maximum autosave frequency is per 60s
-               if(!force && System.nanoTime() - lastSnapshot < 10*1000000000L) {
-//                 System.err.println("lastSnapshot too early");
-                   return false;
-               }
-
-               // Cluster files are always there 
-               // Nothing has been written => no need to do anything
-               long amountOfFiles = countFiles(workingDirectory);
-               if(!force && amountOfFiles < 3) {
-//                 System.err.println("amountOfFiles < 3");
-                   return false;
-               }
-
-               System.err.println("makeSnapshot");
-
-               // Schedule writing of all data to disk
-               refreshHeadState();
-
-               // Wait for all files to be written
-               clusterLRU.shutdown();
-               fileLRU.shutdown();
-               streamLRU.shutdown();
-               csLRU.shutdown();
-               
-               persistHeadState();
-               
-               mainState.save(dbFolder);
-
-               ClusterSetsSupport cssi = locator.getService(ClusterSetsSupport.class); 
-               cssi.save();
-
-               amountOfFiles = countFiles(workingDirectory);
-               
-               System.err.println(" -finished: amount of files is " + amountOfFiles);
-
-               workingDirectory = dbFolder.resolve(Integer.toString(mainState.headDir));
-               if (!Files.exists(workingDirectory)) {
-                   Files.createDirectories(workingDirectory);
-               }
-
-               cssi.updateReadAndWriteDirectories(lastSessionDirectory, workingDirectory);
-
-               clusterLRU.setWriteDir(workingDirectory);
-               fileLRU.setWriteDir(workingDirectory);
-               streamLRU.setWriteDir(workingDirectory);
-               csLRU.setWriteDir(workingDirectory);
-
-               clusterLRU.resume();
-               fileLRU.resume();
-               streamLRU.resume();
-               csLRU.resume();
-
-               lastSnapshot = System.nanoTime();
-               
-               return true;
-               
+       // 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 AtomicBoolean safeToMakeSnapshot = new AtomicBoolean(true);
+       private IllegalAcornStateException cause;
+       
+       public synchronized boolean makeSnapshot(ServiceLocator locator, boolean fullSave) throws IllegalAcornStateException {
+           try {
+           if (!safeToMakeSnapshot.get())
+               throw cause;
+               // Maximum autosave frequency is per 60s
+               if(!fullSave && System.nanoTime() - lastSnapshot < 10*1000000000L) {
+    //             System.err.println("lastSnapshot too early");
+                   return false;
+               }
+    
+               // Cluster files are always there 
+               // Nothing has been written => no need to do anything
+               long amountOfFiles = countFiles(workingDirectory);
+               if(!fullSave && amountOfFiles < 3) {
+    //             System.err.println("amountOfFiles < 3");
+                   return false;
+               }
+    
+               System.err.println("makeSnapshot");
+    
+               // Schedule writing of all data to disk
+            refreshHeadState();
+    
+               // Wait for all files to be written
+               clusterLRU.shutdown();
+               fileLRU.shutdown();
+               streamLRU.shutdown();
+               csLRU.shutdown();
+               
+               // Lets check if it is still safe to make a snapshot
+               if (!safeToMakeSnapshot.get())
+                   throw cause;
+               
+               persistHeadState();
+               
+               if (fullSave)
+                   mainState.save(dbFolder);
+    
+               ClusterSetsSupport cssi = locator.getService(ClusterSetsSupport.class); 
+               cssi.save();
+    
+               amountOfFiles = countFiles(workingDirectory);
+               
+               System.err.println(" -finished: amount of files is " + amountOfFiles);
+    
+               workingDirectory = dbFolder.resolve(Integer.toString(mainState.headDir));
+               if (!Files.exists(workingDirectory)) {
+                   Files.createDirectories(workingDirectory);
+               }
+    
+               cssi.updateWriteDirectory(workingDirectory);
+    
+               clusterLRU.setWriteDir(workingDirectory);
+               fileLRU.setWriteDir(workingDirectory);
+               streamLRU.setWriteDir(workingDirectory);
+               csLRU.setWriteDir(workingDirectory);
+    
+               clusterLRU.resume();
+               fileLRU.resume();
+               streamLRU.resume();
+               csLRU.resume();
+    
+               lastSnapshot = System.nanoTime();
+               
+               return true;
+           } catch (IllegalAcornStateException e) {
+               notSafeToMakeSnapshot(e);
+               throw e;
+           } catch (IOException e) {
+               IllegalAcornStateException e1 = new IllegalAcornStateException(e);
+               notSafeToMakeSnapshot(e1);
+               throw e1;
+           }
        }
        
-       public void refreshHeadState() throws IOException {
-
+       private void refreshHeadState() throws IOException, IllegalAcornStateException {
                state.clusters.clear();
                state.files.clear();
                state.stream.clear();
@@ -197,11 +215,9 @@ public class ClusterManager {
                fileLRU.persist(state.files);
                streamLRU.persist(state.stream);
                csLRU.persist(state.cs);
-
        }
        
-       public void persistHeadState() throws IOException {
-
+       private void persistHeadState() throws IOException {
                // Sync current working directory
                Files.walk(workingDirectory, 1).filter(Files::isRegularFile).forEach(FileIO::uncheckedSyncPath);
                state.save(workingDirectory);
@@ -241,7 +257,7 @@ public class ClusterManager {
 
 //     }
        
-       private void acquireAll() {
+       private void acquireAll() throws IllegalAcornStateException {
                clusterLRU.acquireMutex();
                fileLRU.acquireMutex();
                streamLRU.acquireMutex();
@@ -255,10 +271,16 @@ public class ClusterManager {
                clusterLRU.releaseMutex();
        }
 
+       private AtomicBoolean rollback = new AtomicBoolean(false);
+       
+       boolean rolledback() {
+           return rollback.get();
+       }
+       
        public void load() throws IOException {
 
                // Main state
-               mainState = MainState.load(dbFolder);
+               mainState = MainState.load(dbFolder, t -> rollback.set(true));
 
                lastSessionDirectory = dbFolder.resolve(Integer.toString(mainState.headDir - 1));
                
@@ -292,73 +314,74 @@ public class ClusterManager {
                 throw new IOException("Could not load HeadState due to corruption", e);
             }
         }
-
-               workingDirectory = dbFolder.resolve(Integer.toString(mainState.headDir));
-               Files.createDirectories(workingDirectory);
-
-               csLRU = new LRU<Long, ChangeSetInfo>("Change Set", workingDirectory);
-               streamLRU = new LRU<String, ClusterStreamChunk>("Cluster Stream", workingDirectory);
-               clusterLRU = new ClusterLRU(this, "Cluster", workingDirectory);
-               fileLRU = new LRU<String, FileInfo>("External Value", workingDirectory);
-
-               acquireAll();
-               
-               // Clusters
-               for (String clusterKey : state.clusters) {
-                       String[] parts1 = clusterKey.split("#");
-                       String[] parts = parts1[0].split("\\.");
-                       long first = new BigInteger(parts[0], 16).longValue();
-                       long second = new BigInteger(parts[1], 16).longValue();
-                       ClusterUID uuid = ClusterUID.make(first, second);
-                       Path readDir = dbFolder.resolve(parts1[1]);
-                       int offset = Integer.parseInt(parts1[2]);
-                       int length = Integer.parseInt(parts1[3]);
-                       clusterLRU.map(new ClusterInfo(this, clusterLRU, readDir, uuid, offset, length));
-               }
-               // Files
-               for (String fileKey : state.files) {
-//                     System.err.println("loadFile: " + fileKey);
-                       String[] parts = fileKey.split("#");
-                       Path readDir = dbFolder.resolve(parts[1]);
-                       int offset = Integer.parseInt(parts[2]);
-                       int length = Integer.parseInt(parts[3]);
-                       FileInfo info = new FileInfo(fileLRU, readDir, parts[0], offset, length);
-                       fileLRU.map(info);
-               }
-               // Update chunks
-               for (String fileKey : state.stream) {
-//                     System.err.println("loadStream: " + fileKey);
-                       String[] parts = fileKey.split("#");
-                       Path readDir = dbFolder.resolve(parts[1]);
-                       int offset = Integer.parseInt(parts[2]);
-                       int length = Integer.parseInt(parts[3]);
-                       ClusterStreamChunk info = new ClusterStreamChunk(this,
-                                       streamLRU, readDir, parts[0], offset, length);
-                       streamLRU.map(info);
-               }
-               // Change sets
-               for (String fileKey : state.cs) {
-                       String[] parts = fileKey.split("#");
-                       Path readDir = dbFolder.resolve(parts[1]);
-                       Long revisionId = Long.parseLong(parts[0]);
-                       int offset = Integer.parseInt(parts[2]);
-                       int length = Integer.parseInt(parts[3]);
-                       ChangeSetInfo info = new ChangeSetInfo(csLRU, readDir, revisionId, offset, length);
-                       csLRU.map(info);
+               try {
+               workingDirectory = dbFolder.resolve(Integer.toString(mainState.headDir));
+               Files.createDirectories(workingDirectory);
+    
+               csLRU = new LRU<Long, ChangeSetInfo>(this, "Change Set", workingDirectory);
+               streamLRU = new LRU<String, ClusterStreamChunk>(this, "Cluster Stream", workingDirectory);
+               clusterLRU = new ClusterLRU(this, "Cluster", workingDirectory);
+               fileLRU = new LRU<String, FileInfo>(this, "External Value", workingDirectory);
+    
+               acquireAll();
+               
+               // Clusters
+               for (String clusterKey : state.clusters) {
+                       String[] parts1 = clusterKey.split("#");
+                       String[] parts = parts1[0].split("\\.");
+                       long first = new BigInteger(parts[0], 16).longValue();
+                       long second = new BigInteger(parts[1], 16).longValue();
+                       ClusterUID uuid = ClusterUID.make(first, second);
+                       Path readDir = dbFolder.resolve(parts1[1]);
+                       int offset = Integer.parseInt(parts1[2]);
+                       int length = Integer.parseInt(parts1[3]);
+                       clusterLRU.map(new ClusterInfo(this, clusterLRU, readDir, uuid, offset, length));
+               }
+               // Files
+               for (String fileKey : state.files) {
+    //                 System.err.println("loadFile: " + fileKey);
+                       String[] parts = fileKey.split("#");
+                       Path readDir = dbFolder.resolve(parts[1]);
+                       int offset = Integer.parseInt(parts[2]);
+                       int length = Integer.parseInt(parts[3]);
+                       FileInfo info = new FileInfo(fileLRU, readDir, parts[0], offset, length);
+                       fileLRU.map(info);
+               }
+               // Update chunks
+               for (String fileKey : state.stream) {
+    //                 System.err.println("loadStream: " + fileKey);
+                       String[] parts = fileKey.split("#");
+                       Path readDir = dbFolder.resolve(parts[1]);
+                       int offset = Integer.parseInt(parts[2]);
+                       int length = Integer.parseInt(parts[3]);
+                       ClusterStreamChunk info = new ClusterStreamChunk(this,
+                                       streamLRU, readDir, parts[0], offset, length);
+                       streamLRU.map(info);
+               }
+               // Change sets
+               for (String fileKey : state.cs) {
+                       String[] parts = fileKey.split("#");
+                       Path readDir = dbFolder.resolve(parts[1]);
+                       Long revisionId = Long.parseLong(parts[0]);
+                       int offset = Integer.parseInt(parts[2]);
+                       int length = Integer.parseInt(parts[3]);
+                       ChangeSetInfo info = new ChangeSetInfo(csLRU, readDir, revisionId, offset, length);
+                       csLRU.map(info);
+               }
+               
+               releaseAll();
+               } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
+                   // ROLLBACK ONE DIR UNTIL WE ARE FINE!
+                   throw new IOException(e);
                }
-               
-               releaseAll();
-
        }
 
-       public <T> T clone(ClusterUID uid, ClusterCreator creator)
-                       throws DatabaseException {
+       public <T> T clone(ClusterUID uid, ClusterCreator creator) throws DatabaseException, AcornAccessVerificationException, IllegalAcornStateException, IOException {
                
                clusterLRU.ensureUpdates(uid);
                
                ClusterInfo info = clusterLRU.getWithoutMutex(uid);
                return info.clone(uid, creator);
-
        }
 
        //private int loadCounter = 0;
@@ -375,38 +398,32 @@ public class ClusterManager {
 
        static Map<String, ITask> tasks = new HashMap<String, ITask>();
 
-       public void update(ClusterUID uid, ClusterImpl clu) {
-
+       public void update(ClusterUID uid, ClusterImpl clu) throws AcornAccessVerificationException, IllegalAcornStateException {
                ClusterInfo info = clusterLRU.getWithoutMutex(uid);
                info.acquireMutex();
                try {
                        info.update(clu);
-               } catch (Throwable t) {
-                       throw new IllegalStateException(t);
                } finally {
                        info.releaseMutex();
                }
-               
        }
 
        public long getClusterIdOrCreate(ClusterUID clusterUID) {
                return 1;
        }
 
-       public int getResourceKey(ClusterUID uid, int index) {
+       public int getResourceKey(ClusterUID uid, int index) throws AcornAccessVerificationException {
                return clusterLRU.getResourceKey(uid, index);
        }
 
-       public int getResourceKeyWitoutMutex(ClusterUID uid, int index) {
+       public int getResourceKeyWitoutMutex(ClusterUID uid, int index) throws IllegalAcornStateException {
                return clusterLRU.getResourceKeyWithoutMutex(uid, index);
        }
 
-       public ClusterIds getClusterIds() throws ProCoreException {
-
+       public ClusterIds getClusterIds() throws IllegalAcornStateException {
                clusterLRU.acquireMutex();
 
                try {
-
                        Collection<ClusterInfo> infos = clusterLRU.values();
                        final int status = infos.size();
                        final long[] firsts = new long[status];
@@ -439,61 +456,54 @@ public class ClusterManager {
                        };
 
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
                        clusterLRU.releaseMutex();
                }
-
        }
 
-       public void addIntoCurrentChangeSet(String ccs) {
-               
+       public void addIntoCurrentChangeSet(String ccs) throws IllegalAcornStateException {
                csLRU.acquireMutex();
 
                try {
-                       
                        currentChanges.add(ccs);
-                       
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
-                       
                        csLRU.releaseMutex();
-                       
                }
-
        }
 
-       public void commitChangeSet(long changeSetId, byte[] data) {
+       public void commitChangeSet(long changeSetId, byte[] data) throws IllegalAcornStateException {
                csLRU.acquireMutex();
                try {
                        ArrayList<String> csids = new ArrayList<String>(currentChanges);
                        currentChanges = new ArrayList<String>();
                        new ChangeSetInfo(csLRU, changeSetId, data, csids);
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
                        csLRU.releaseMutex();
                }
        }
 
-       public byte[] getMetadata(long changeSetId) {
+       public byte[] getMetadata(long changeSetId) throws AcornAccessVerificationException, IllegalAcornStateException {
                
                ChangeSetInfo info = csLRU.getWithoutMutex(changeSetId);
                if (info == null) return null;
-               info.acquireMutex();
-               try {
-                       return info.getMetadataBytes();
-               } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+        info.acquireMutex();
+        try {
+            return info.getMetadataBytes();
+        } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
+            throw e;
+        } catch (Throwable t) {
+                       throw new IllegalAcornStateException(t);
                } finally {
                        info.releaseMutex();
                }
-               
        }
 
-       public byte[] getResourceFile(final byte[] clusterUID,
-                       final int resourceIndex) throws ProCoreException {
+       public byte[] getResourceFile(final byte[] clusterUID, final int resourceIndex) throws AcornAccessVerificationException, IllegalAcornStateException {
 
                ClusterUID uid = ClusterUID.make(clusterUID, 0);
                String key = uid.toString() + "_" + resourceIndex;
@@ -502,18 +512,16 @@ public class ClusterManager {
                info.acquireMutex();
                try {
                        return info.getResourceFile();
+               } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
+                   throw e;
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
                        info.releaseMutex();
                }
-
        }
 
-       public ResourceSegment getResourceSegment(final byte[] clusterUID,
-                       final int resourceIndex, final long segmentOffset, short segmentSize)
-                       throws ProCoreException {
-
+       public ResourceSegment getResourceSegment(final byte[] clusterUID, final int resourceIndex, final long segmentOffset, short segmentSize) throws AcornAccessVerificationException, IllegalAcornStateException {
                ClusterUID uid = ClusterUID.make(clusterUID, 0);
 
                String key = uid.toString() + "_" + resourceIndex;
@@ -523,55 +531,40 @@ public class ClusterManager {
                try {
                        return info.getResourceSegment(clusterUID, resourceIndex, segmentOffset, segmentSize);
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
                        info.releaseMutex();
                }
-
        }
 
-       public void modiFileEx(ClusterUID uid, int resourceKey, long offset,
-                       long size, byte[] bytes, long pos, ClusterSupport support) {
-
+       public void modiFileEx(ClusterUID uid, int resourceKey, long offset, long size, byte[] bytes, long pos, ClusterSupport support) throws IllegalAcornStateException {
                try {
-
-                       String key = uid.toString()
-                                       + "_"
-                                       + ClusterTraits
-                                                       .getResourceIndexFromResourceKey(resourceKey);
+                       String key = uid.toString() + "_" + ClusterTraits.getResourceIndexFromResourceKey(resourceKey);
 
                        FileInfo info = null;
-
                        fileLRU.acquireMutex();
-
                        try {
-
                                info = fileLRU.get(key);
-                               if (info == null)
+                               if (info == null) {
                                        info = new FileInfo(fileLRU, key, (int) (offset + size));
-                               
-                               
+                               }
                        } catch (Throwable t) {
-                               throw new IllegalStateException(t);
+                               throw new IllegalAcornStateException(t);
                        } finally {
-                               
                                fileLRU.releaseMutex();
-                               
                        }
                        
                        info.acquireMutex();
                        try {
                                info.updateData(bytes, offset, pos, size);
                        } catch (Throwable t) {
-                               throw new IllegalStateException(t);
+                               throw new IllegalAcornStateException(t);
                        } finally {
                                info.releaseMutex();
                        }
-
                } catch (DatabaseException e) {
                        e.printStackTrace();
                }
-
        }
 
     public void shutdown() {
@@ -581,4 +574,9 @@ public class ClusterManager {
         csLRU.shutdown();
     }
 
+    public void notSafeToMakeSnapshot(IllegalAcornStateException t) {
+        this.safeToMakeSnapshot.compareAndSet(true, false);
+        this.cause = t;
+    }
+
 }
index aa71732855bab8a6108d9fa2d837ebb3798a2839..c5480d86ec6c636233b5e5b21d8d5e688f319966 100644 (file)
@@ -66,15 +66,17 @@ public class FileIO {
                ByteBuffer bb = ByteBuffer.wrap(bytes, 0, length);
                try (FileChannel fc = FileChannel.open(path, options, NO_ATTRIBUTES)) {
             fc.write(bb);
+            
+            writePosition += length;
+            if(TRACE_PERF) {
+                long duration = System.nanoTime()-start;
+                double ds = 1e-9*duration;
+                System.err.println("Wrote " + bytes.length + " bytes @ " + 1e-6*bytes.length / ds + "MB/s");
+            }
+            return result;
+               } catch (Throwable t) {
+                   throw new IOException("An error occured file saving bytes for file " + path.toAbsolutePath().toString(), t);
                }
-               
-        writePosition += length;
-               if(TRACE_PERF) {
-                       long duration = System.nanoTime()-start;
-                       double ds = 1e-9*duration;
-                       System.err.println("Wrote " + bytes.length + " bytes @ " + 1e-6*bytes.length / ds + "MB/s");
-               }
-               return result;
        }
 
     public synchronized byte[] readBytes(int offset, int length) throws IOException {
index 774b605541371766333fa19957e57171bc40fdab..05f9c8de00b66c315f9a6c5317026f28c0c664cb 100644 (file)
@@ -21,6 +21,8 @@ import java.util.concurrent.Semaphore;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.acorn.internal.ClusterChange;
 import org.simantics.acorn.internal.ClusterUpdateProcessorBase;
 import org.simantics.acorn.internal.UndoClusterUpdateProcessor;
@@ -37,6 +39,7 @@ import org.simantics.db.exception.SDBException;
 import org.simantics.db.server.ProCoreException;
 import org.simantics.db.service.ClusterSetsSupport;
 import org.simantics.db.service.ClusterUID;
+import org.simantics.db.service.LifecycleSupport;
 import org.simantics.utils.datastructures.Pair;
 import org.simantics.utils.logging.TimeLogger;
 
@@ -52,7 +55,6 @@ public class GraphClientImpl2 implements Database.Session {
        private ExecutorService executor = Executors.newSingleThreadExecutor(new ClientThreadFactory("Core Main Program", false));
        private ExecutorService saver = Executors.newSingleThreadExecutor(new ClientThreadFactory("Core Snapshot Saver", true));
 
-       private static GraphClientImpl2 INSTANCE;
        private Path dbFolder;
        private final Database database;
        private ServiceLocator locator;
@@ -83,10 +85,9 @@ public class GraphClientImpl2 implements Database.Session {
            this.clusters = new ClusterManager(dbFolder);
            load();
            ClusterSetsSupport cssi = locator.getService(ClusterSetsSupport.class); 
-           cssi.updateReadAndWriteDirectories(clusters.lastSessionDirectory, clusters.workingDirectory);
+           cssi.setReadDirectory(clusters.lastSessionDirectory);
            mainProgram = new MainProgram(this, clusters);
            executor.execute(mainProgram);
-           INSTANCE = this;
        }
 
        public Path getDbFolder() {
@@ -95,7 +96,7 @@ public class GraphClientImpl2 implements Database.Session {
 
        public void tryMakeSnapshot() throws IOException {
                
-           if (isClosing)
+           if (isClosing || unexpectedClose)
                return;
            
                saver.execute(new Runnable() {
@@ -120,32 +121,42 @@ public class GraphClientImpl2 implements Database.Session {
                                        } finally {
                                                mainProgram.mutex.release();
                                        }
-                               } catch (IOException e) {
-                                       Logger.defaultLogError(e);
-                               } catch (ProCoreException e) {
+                               } catch (IllegalAcornStateException | ProCoreException e) {
                                        Logger.defaultLogError(e);
+                                       unexpectedClose = true;
                                } catch (InterruptedException e) {
                                        Logger.defaultLogError(e);
                                } finally {
                                        try {
                                                if(tr != null)
                                                        endTransaction(tr.getTransactionId());
+                                               if (unexpectedClose) {
+                                               LifecycleSupport support = getServiceLocator().getService(LifecycleSupport.class);
+                           try {
+                               support.close();
+                           } catch (DatabaseException e1) {
+                               Logger.defaultLogError(e1);
+                           }
+                                               }
                                        } catch (ProCoreException e) {
                                                Logger.defaultLogError(e);
                                        }
                                }
                        }
-                       
                });
        }
        
-    public void makeSnapshot(boolean force) throws IOException {
-        if (safeToMakeSnapshot)
-            clusters.makeSnapshot(locator, force);
+    public void makeSnapshot(boolean fullSave) throws IllegalAcornStateException {
+        clusters.makeSnapshot(locator, fullSave);
     }
        
        public <T> T clone(ClusterUID uid, ClusterCreator creator) throws DatabaseException {
-               return clusters.clone(uid, creator);
+           try {
+            return clusters.clone(uid, creator);
+        } catch (AcornAccessVerificationException | IllegalAcornStateException | IOException e) {
+            unexpectedClose = true;
+            throw new DatabaseException(e);
+        }
        }
 
 //     private void save() throws IOException {
@@ -167,8 +178,7 @@ 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;
+       private boolean unexpectedClose = false;
        
        @Override
        public void close() throws ProCoreException {
@@ -176,7 +186,8 @@ public class GraphClientImpl2 implements Database.Session {
                if(!closed && !isClosing) {
                    isClosing = true;
                        try {
-                           makeSnapshot(true);
+                           if (!unexpectedClose)
+                               makeSnapshot(true);
                                
                                mainProgram.close();
                                clusters.shutdown();
@@ -187,16 +198,15 @@ public class GraphClientImpl2 implements Database.Session {
                                
                                System.err.println("executorTerminated=" + executorTerminated + ", saverTerminated=" + saverTerminated);
                                
-                               INSTANCE = null;
                                mainProgram = null;
                                executor = null;
                                saver = null;
                                
-                       } catch (IOException | InterruptedException e) {
+                       } catch (IllegalAcornStateException | InterruptedException e) {
                                throw new ProCoreException(e);
                        }
+                       closed = true;
                }
-               closed = true;
                //impl.close();
        }
 
@@ -212,27 +222,26 @@ public class GraphClientImpl2 implements Database.Session {
        
        @Override
        public void acceptCommit(long transactionId, long changeSetId, byte[] metadata) throws ProCoreException {
-               
                clusters.state.headChangeSetId++;
-
                long committedChangeSetId = changeSetId + 1;
-               
-               clusters.commitChangeSet(committedChangeSetId, metadata);
-               
-               clusters.state.transactionId = transactionId;
-               
-               mainProgram.committed();
-               
-               TimeLogger.log("Accepted commit");
-               
+               try {
+               clusters.commitChangeSet(committedChangeSetId, metadata);
+               
+               clusters.state.transactionId = transactionId;
+               
+               mainProgram.committed();
+               
+               TimeLogger.log("Accepted commit");
+               } catch (IllegalAcornStateException e) {
+                   throw new ProCoreException(e);
+               }
        }
 
        @Override
-       public long cancelCommit(long transactionId, long changeSetId,
-                       byte[] metadata, OnChangeSetUpdate onChangeSetUpdate)
-                       throws ProCoreException {
-           safeToMakeSnapshot = false;
-           throw new UnsupportedOperationException("org.simantics.acorn.GraphClientImpl2.cancelCommit() is not supported operation! Closing down to prevent further havoc");
+       public long cancelCommit(long transactionId, long changeSetId, byte[] metadata, OnChangeSetUpdate onChangeSetUpdate) throws ProCoreException {
+           UnsupportedOperationException e = new UnsupportedOperationException("org.simantics.acorn.GraphClientImpl2.cancelCommit() is not supported operation! Closing down to prevent further havoc");
+           clusters.notSafeToMakeSnapshot(new IllegalAcornStateException(e));
+           throw e;
 //         System.err.println("GraphClientImpl2.cancelCommit() called!! this is experimental and might cause havoc!");
 //         try {
 //            undo(new long[] {changeSetId}, onChangeSetUpdate);
@@ -366,23 +375,18 @@ public class GraphClientImpl2 implements Database.Session {
                 * This method cannot be synchronized since it waits and must support multiple entries
                 * by query thread(s) and internal transactions such as snapshot saver
                 */
-               public Transaction askWriteTransaction()
-                               throws ProCoreException {
+               public Transaction askWriteTransaction() throws IllegalAcornStateException {
                        
                        Semaphore semaphore = new Semaphore(0);
-                       
                        TransactionRequest req = queue(TransactionState.WRITE, semaphore);
                        
                        try {
                                semaphore.acquire();
                        } catch (InterruptedException e) {
-                               throw new ProCoreException(e);
+                               throw new IllegalAcornStateException(e);
                        }
-                       
                        mainProgram.startTransaction(clusters.state.headChangeSetId+1);
-                       
                        return makeTransaction(req);
-                       
                }
                
                public synchronized long endTransaction(long transactionId) throws ProCoreException {
@@ -404,9 +408,15 @@ public class GraphClientImpl2 implements Database.Session {
        }
        
        @Override
-       public Transaction askWriteTransaction(final long transactionId)
-                       throws ProCoreException {
-               return transactionManager.askWriteTransaction();
+       public Transaction askWriteTransaction(final long transactionId) throws ProCoreException {
+               try {
+                   if (isClosing || unexpectedClose || closed) {
+                       throw new ProCoreException("GraphClientImpl2 is already closing so no more write transactions allowed!");
+                   }
+            return transactionManager.askWriteTransaction();
+        } catch (IllegalAcornStateException e) {
+            throw new ProCoreException(e);
+        }
        }
 
        @Override
@@ -422,9 +432,12 @@ public class GraphClientImpl2 implements Database.Session {
        }
 
        @Override
-       public byte[] getChangeSetMetadata(long changeSetId)
-                       throws ProCoreException {
-               return clusters.getMetadata(changeSetId);
+       public byte[] getChangeSetMetadata(long changeSetId) throws ProCoreException {
+               try {
+            return clusters.getMetadata(changeSetId);
+        } catch (AcornAccessVerificationException | IllegalAcornStateException e) {
+            throw new ProCoreException(e);
+        }
        }
 
        @Override
@@ -455,7 +468,11 @@ public class GraphClientImpl2 implements Database.Session {
 
        @Override
        public ClusterIds getClusterIds() throws ProCoreException {
-               return clusters.getClusterIds();
+               try {
+            return clusters.getClusterIds();
+        } catch (IllegalAcornStateException e) {
+            throw new ProCoreException(e);
+        }
        }
 
        @Override
@@ -511,16 +528,17 @@ public class GraphClientImpl2 implements Database.Session {
                
        }
 
-       public byte[] getResourceFile(final byte[] clusterUID, final int resourceIndex) throws ProCoreException {
+       public byte[] getResourceFile(final byte[] clusterUID, final int resourceIndex) throws ProCoreException, AcornAccessVerificationException, IllegalAcornStateException {
                return clusters.getResourceFile(clusterUID, resourceIndex);
        }
 
        @Override
-       public ResourceSegment getResourceSegment(final byte[] clusterUID,
-                       final int resourceIndex, final long segmentOffset, short segmentSize) throws ProCoreException {
-               
-               return clusters.getResourceSegment(clusterUID, resourceIndex, segmentOffset, segmentSize);
-
+       public ResourceSegment getResourceSegment(final byte[] clusterUID, final int resourceIndex, final long segmentOffset, short segmentSize) throws ProCoreException {
+               try {
+            return clusters.getResourceSegment(clusterUID, resourceIndex, segmentOffset, segmentSize);
+        } catch (AcornAccessVerificationException | IllegalAcornStateException e) {
+            throw new ProCoreException(e);
+        }
        }
 
        @Override
@@ -530,42 +548,43 @@ public class GraphClientImpl2 implements Database.Session {
 
        @Override
        public void updateCluster(byte[] operations) throws ProCoreException {
-
-               ClusterUpdateOperation operation = new ClusterUpdateOperation(clusters, operations);
-               ClusterInfo info = clusters.clusterLRU.getOrCreate(operation.uid, true);
-               if(info == null) throw new IllegalStateException();
-               info.acquireMutex();
-               try {
+           ClusterInfo info = null;
+           try {
+               ClusterUpdateOperation operation = new ClusterUpdateOperation(clusters, operations);
+               info = clusters.clusterLRU.getOrCreate(operation.uid, true);
+               if(info == null)
+                   throw new IllegalAcornStateException("info == null for operation " + operation);
+               info.acquireMutex();
                        info.scheduleUpdate();
                        mainProgram.schedule(operation);
-               } catch (Throwable t) {
-                       throw new IllegalStateException(t);
-               } finally {
-                       info.releaseMutex();
+               } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
+            throw new ProCoreException(e);
+        } finally {
+            if (info != null)
+                info.releaseMutex();
                }
-
        }
 
-       private UndoClusterUpdateProcessor getUndoCSS(String ccsId) throws DatabaseException {
+       private UndoClusterUpdateProcessor getUndoCSS(String ccsId) throws DatabaseException, AcornAccessVerificationException, IllegalAcornStateException {
 
                String[] ss = ccsId.split("\\.");
                String chunkKey = ss[0];
                int chunkOffset = Integer.parseInt(ss[1]);
                ClusterStreamChunk chunk = clusters.streamLRU.getWithoutMutex(chunkKey);
-               if(chunk == null) throw new IllegalStateException("Cluster Stream Chunk " + chunkKey + " was not found.");
+               if(chunk == null) throw new IllegalAcornStateException("Cluster Stream Chunk " + chunkKey + " was not found.");
                chunk.acquireMutex();
                try {
                        return chunk.getUndoProcessor(clusters, chunkOffset, ccsId);
+               } catch (DatabaseException e) {
+                   throw e;
                } catch (Throwable t) {
                        throw new IllegalStateException(t);
                } finally {
                        chunk.releaseMutex();
                }
-               
        }
        
-       private void performUndo(String ccsId, ArrayList<Pair<ClusterUID, byte[]>> clusterChanges, UndoClusterSupport support) throws ProCoreException, DatabaseException {
-
+       private void performUndo(String ccsId, ArrayList<Pair<ClusterUID, byte[]>> clusterChanges, UndoClusterSupport support) throws ProCoreException, DatabaseException, IllegalAcornStateException, AcornAccessVerificationException {
                UndoClusterUpdateProcessor proc = getUndoCSS(ccsId);
 
                int clusterKey = clusters.getClusterKeyByClusterUIDOrMakeWithoutMutex(proc.getClusterUID());
@@ -578,103 +597,96 @@ public class GraphClientImpl2 implements Database.Session {
                                
                                Entry e = proc.entries.get(proc.entries.size() - 1 - i);
                                e.process(clusters, cs, clusterKey);
-                               
                        }
-                       
                        cs.flush();
 
                } finally {
                        clusters.clusterLRU.releaseMutex();
                }
-               
        }
        
        @Override
        public boolean undo(long[] changeSetIds, OnChangeSetUpdate onChangeSetUpdate) throws SDBException {
-               
-               final ArrayList<Pair<ClusterUID, byte[]>> clusterChanges = new ArrayList<Pair<ClusterUID, byte[]>>();
-               
-               UndoClusterSupport support = new UndoClusterSupport(clusters);
-               
-               final int changeSetId = clusters.state.headChangeSetId;
-               
-               if(ClusterUpdateProcessorBase.DEBUG)
-                       System.err.println(" === BEGIN UNDO ===");
-               
-               for(int i=0;i<changeSetIds.length;i++) {
-                       final long id = changeSetIds[changeSetIds.length-1-i];
-                       ArrayList<String> ccss = clusters.getChanges(id);
-                       for(int j=0;j<ccss.size();j++) {
-                               try {
-                                       if(ClusterUpdateProcessorBase.DEBUG)
-                                               System.err.println("performUndo " + ccss.get(ccss.size()-j-1));
-                                       performUndo(ccss.get(ccss.size()-j-1), clusterChanges, support);
-                               } catch (DatabaseException e) {
-                                       e.printStackTrace();
-                               }
-                       }
-               }
-
-               if(ClusterUpdateProcessorBase.DEBUG)
-                       System.err.println(" === END UNDO ===");
-
-               for(int i=0;i<clusterChanges.size();i++) {
-                       
-                       final int changeSetIndex = i;
-                       
-                       final Pair<ClusterUID, byte[]> pair = clusterChanges.get(i);
-                       
-                       final ClusterUID cuid = pair.first;
-                       final byte[] data = pair.second;
-
-                       onChangeSetUpdate.onChangeSetUpdate(new ChangeSetUpdate() {
-
-                               @Override
-                               public long getChangeSetId() {
-                                       return changeSetId;
-                               }
-
-                               @Override
-                               public int getChangeSetIndex() {
-                                       return 0;
-                               }
-
-                               @Override
-                               public int getNumberOfClusterChangeSets() {
-                                       return clusterChanges.size();
-                               }
-
-                               @Override
-                               public int getIndexOfClusterChangeSet() {
-                                       return changeSetIndex;
-                               }
-
-                               @Override
-                               public byte[] getClusterId() {
-                                       return cuid.asBytes();
-                               }
-
-                               @Override
-                               public boolean getNewCluster() {
-                                       return false;
-                               }
-
-                               @Override
-                               public byte[] getData() {
-                                       return data;
-                               }
-
-                       });
-
-               }
-
-               
+           try {
+               final ArrayList<Pair<ClusterUID, byte[]>> clusterChanges = new ArrayList<Pair<ClusterUID, byte[]>>();
+               
+               UndoClusterSupport support = new UndoClusterSupport(clusters);
+               
+               final int changeSetId = clusters.state.headChangeSetId;
+               
+               if(ClusterUpdateProcessorBase.DEBUG)
+                       System.err.println(" === BEGIN UNDO ===");
+               
+               for(int i=0;i<changeSetIds.length;i++) {
+                       final long id = changeSetIds[changeSetIds.length-1-i];
+                       ArrayList<String> ccss = clusters.getChanges(id);
+    
+                       for(int j=0;j<ccss.size();j++) {
+                               try {
+                                       if(ClusterUpdateProcessorBase.DEBUG)
+                                               System.err.println("performUndo " + ccss.get(ccss.size()-j-1));
+                                       performUndo(ccss.get(ccss.size()-j-1), clusterChanges, support);
+                               } catch (DatabaseException e) {
+                                       e.printStackTrace();
+                               }
+                       }
+               }
+    
+               if(ClusterUpdateProcessorBase.DEBUG)
+                       System.err.println(" === END UNDO ===");
+    
+               for(int i=0;i<clusterChanges.size();i++) {
+                       
+                       final int changeSetIndex = i;
+                       
+                       final Pair<ClusterUID, byte[]> pair = clusterChanges.get(i);
+                       
+                       final ClusterUID cuid = pair.first;
+                       final byte[] data = pair.second;
+    
+                       onChangeSetUpdate.onChangeSetUpdate(new ChangeSetUpdate() {
+    
+                               @Override
+                               public long getChangeSetId() {
+                                       return changeSetId;
+                               }
+    
+                               @Override
+                               public int getChangeSetIndex() {
+                                       return 0;
+                               }
+    
+                               @Override
+                               public int getNumberOfClusterChangeSets() {
+                                       return clusterChanges.size();
+                               }
+    
+                               @Override
+                               public int getIndexOfClusterChangeSet() {
+                                       return changeSetIndex;
+                               }
+    
+                               @Override
+                               public byte[] getClusterId() {
+                                       return cuid.asBytes();
+                               }
+    
+                               @Override
+                               public boolean getNewCluster() {
+                                       return false;
+                               }
+    
+                               @Override
+                               public byte[] getData() {
+                                       return data;
+                               }
+    
+                       });
+               }
+        } catch (AcornAccessVerificationException | IllegalAcornStateException e1) {
+            throw new ProCoreException(e1);
+        }
                return false;
-               
-       }
-       
-       public static GraphClientImpl2 getInstance() {
-           return INSTANCE;
        }
        
        public ServiceLocator getServiceLocator() {
@@ -686,6 +698,11 @@ public class GraphClientImpl2 implements Database.Session {
         return false;
     }
 
+    @Override
+    public boolean rolledback() {
+        return clusters.rolledback();
+    }
+
        
        
        
index c20d8e878a4eec04ebaa26ab892efa1790aea431..dd8703c1fc689e0ed0bbfc1968e6730913d74750 100644 (file)
@@ -1,7 +1,6 @@
 package org.simantics.acorn;
 
 import java.io.ByteArrayInputStream;
-import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.file.Files;
@@ -11,6 +10,7 @@ import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Arrays;
 
+import org.simantics.acorn.exception.InvalidHeadStateException;
 import org.simantics.databoard.Bindings;
 import org.simantics.databoard.binding.mutable.MutableVariant;
 import org.simantics.databoard.serialization.Serializer;
@@ -18,6 +18,9 @@ import org.simantics.databoard.util.binary.BinaryMemory;
 
 public class HeadState {
 
+    public static final String HEAD_STATE = "head.state";
+    public static final String SHA_1 = "SHA-1";
+    
     public int headChangeSetId = 0;
     public long transactionId = 1;
     public long reservedIds = 3;
@@ -29,11 +32,11 @@ public class HeadState {
 //    public ArrayList<String> ccs = new ArrayList<String>();
 
     public static HeadState load(Path directory) throws InvalidHeadStateException {
-        Path f = directory.resolve("head.state");
+        Path f = directory.resolve(HEAD_STATE);
         
         try {
             byte[] bytes = Files.readAllBytes(f);
-            MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
+            MessageDigest sha1 = MessageDigest.getInstance(SHA_1);
             int digestLength = sha1.getDigestLength();
             
             sha1.update(bytes, digestLength, bytes.length - digestLength);
@@ -43,10 +46,10 @@ public class HeadState {
                         "Checksum " + Arrays.toString(newChecksum) + " does not match excpected "
                                 + Arrays.toString(Arrays.copyOfRange(bytes, 0, digestLength)) + " for " + f.toAbsolutePath());
             }
-            
-            HeadState object = (HeadState) org.simantics.databoard.Files.readFile(new ByteArrayInputStream(bytes, digestLength, bytes.length - digestLength), Bindings.getBindingUnchecked(HeadState.class));
-            return object;
-            
+            try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes, digestLength, bytes.length - digestLength)) {
+                HeadState object = (HeadState) org.simantics.databoard.Files.readFile(bais, Bindings.getBindingUnchecked(HeadState.class));
+                return object;
+            }
         } catch (IOException i) {
             return new HeadState();
 //            throw new InvalidHeadStateException(i);
@@ -58,7 +61,7 @@ public class HeadState {
     }
     
     public void save(Path directory) throws IOException {
-        Path f = directory.resolve("head.state");
+        Path f = directory.resolve(HEAD_STATE);
         try {
             BinaryMemory rf = new BinaryMemory(4096);
             try {
@@ -71,7 +74,7 @@ public class HeadState {
             
             byte[] bytes = rf.toByteBuffer().array();
             
-            MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
+            MessageDigest sha1 = MessageDigest.getInstance(SHA_1);
             sha1.update(bytes);
             byte[] checksum = sha1.digest();
             
@@ -88,7 +91,7 @@ public class HeadState {
     public static void validateHeadStateIntegrity(Path headState) throws InvalidHeadStateException, IOException {
         try {
             byte[] bytes = Files.readAllBytes(headState);
-            MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
+            MessageDigest sha1 = MessageDigest.getInstance(SHA_1);
             int digestLength = sha1.getDigestLength();
             sha1.update(bytes, digestLength, bytes.length - digestLength);
             byte[] newChecksum = sha1.digest();
index f39a4987d2ecc27e77843d256e2106d7f2d3e2a3..78ff9e8995c4162fc347edc9b51bd6f7c69ec4ff 100644 (file)
@@ -7,12 +7,15 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
+import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.acorn.lru.ClusterStreamChunk;
 import org.simantics.acorn.lru.ClusterUpdateOperation;
 import org.simantics.db.service.ClusterUID;
@@ -167,9 +170,7 @@ public class MainProgram implements Runnable, Closeable {
                                                } catch (InterruptedException e) {
                                                        e.printStackTrace();
                                                }
-
                                        }
-
                                }
 
 //                             long sss = System.nanoTime();
@@ -191,19 +192,27 @@ public class MainProgram implements Runnable, Closeable {
                                        final List<ClusterUpdateOperation> ops = updateSchedules[i];
                                        if (!ops.isEmpty()) {
                                                acquireAmount++;
-                                               clusterUpdateThreads[i].execute(() -> {
-
-                                                       //long st = System.nanoTime();
-                                                       for(ClusterUpdateOperation op : ops) {
-                                                               op.run();
-                                                       }
-                                                       s.release();
-                                                       //                                                      long duration = System.nanoTime()-st;
-                                                       //                                                      elapsed.addAndGet(duration);
-                                                       //                                                      double dur = 1e-9*duration;
-                                                       //                                                      if(dur > 0.05)
-                                                       //                                                              System.err.println("duration=" + dur + "s. " + ops.size());
-                                               });
+                                               clusterUpdateThreads[i].submit(new Callable<Object>() {
+
+                            @Override
+                            public Object call() throws Exception {
+                                //long st = System.nanoTime();
+                                try {
+                                    for(ClusterUpdateOperation op : ops) {
+                                        op.run();
+                                    }
+                                } finally {
+                                    s.release();
+                                }
+                                return null;
+                                
+    //                          long duration = System.nanoTime()-st;
+    //                          elapsed.addAndGet(duration);
+    //                          double dur = 1e-9*duration;
+    //                          if(dur > 0.05)
+    //                              System.err.println("duration=" + dur + "s. " + ops.size());
+                            }
+                        });
                                        }
                                }
 
@@ -217,8 +226,8 @@ public class MainProgram implements Runnable, Closeable {
                                clusters.streamLRU.acquireMutex();
                                try {
                                        swapChunks();
-                               } catch (Throwable t) {
-                                       throw new IllegalStateException(t);
+                               } catch (AcornAccessVerificationException | IllegalAcornStateException e) {
+                                   e.printStackTrace();
                                } finally {
                                        clusters.streamLRU.releaseMutex();
                                }
@@ -226,7 +235,7 @@ public class MainProgram implements Runnable, Closeable {
                                try {
                                        swapCS();
                                } catch (Throwable t) {
-                                       throw new IllegalStateException(t);
+                                       throw new IllegalAcornStateException(t);
                                } finally {
                                        clusters.csLRU.releaseMutex();
                                }
@@ -240,31 +249,28 @@ public class MainProgram implements Runnable, Closeable {
                } finally {
                        deathBarrier.release();
                }
-
        }
 
        /*
         * Mutex for streamLRU is assumed here
         * 
         */
-       private void swapChunks() {
+       private void swapChunks() throws AcornAccessVerificationException, IllegalAcornStateException {
 
                // Cache chunks during update operations
                boolean written = clusters.streamLRU.swap(Integer.MAX_VALUE, CHUNK_CACHE_SIZE);
                while(written) {
                        written = clusters.streamLRU.swap(Integer.MAX_VALUE, CHUNK_CACHE_SIZE);
                }
-
        }
 
-       private void swapCS() {
+       private void swapCS() throws AcornAccessVerificationException, IllegalAcornStateException {
 
                // Cache chunks during update operations
                boolean written = clusters.csLRU.swap(Integer.MAX_VALUE, CHUNK_CACHE_SIZE);
                while(written) {
                        written = clusters.csLRU.swap(Integer.MAX_VALUE, CHUNK_CACHE_SIZE);
                }
-
        }
 
        public synchronized void committed() {
@@ -278,7 +284,7 @@ public class MainProgram implements Runnable, Closeable {
 
        }
 
-       public synchronized void schedule(ClusterUpdateOperation operation) {
+       public synchronized void schedule(ClusterUpdateOperation operation) throws IllegalAcornStateException {
            if (!alive) {
                System.err.println("Trying to schedule operation after MainProgram is closed! Operation is " + operation);
 //             return;
@@ -303,15 +309,13 @@ public class MainProgram implements Runnable, Closeable {
                        swapChunks();
 
                        notifyAll();
-
+               } catch (IllegalAcornStateException e) {
+                   throw e;
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
-
                        clusters.streamLRU.releaseMutex();
-
                }
-
        }
 
     @Override
index 77335289d73b446b6f10b20a0f1a03ce930ce4f0..ec8451cca78adfef37ea4377cd1fad26e2eff89f 100644 (file)
@@ -1,69 +1,96 @@
 package org.simantics.acorn;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
+import java.io.OutputStream;
 import java.io.Serializable;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.List;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import org.simantics.acorn.exception.InvalidHeadStateException;
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.binding.mutable.MutableVariant;
 import org.simantics.databoard.file.RuntimeIOException;
+import org.simantics.databoard.serialization.Serializer;
+import org.simantics.databoard.util.binary.BinaryMemory;
 import org.simantics.utils.FileUtils;
 
 public class MainState implements Serializable {
 
     private static final long serialVersionUID = 6237383147637270225L;
 
+    public static final String MAIN_STATE = "main.state";
+    
     public int headDir = 0;
 
     public MainState() {
     }
-
-    public MainState(int headDir) {
+    
+    private MainState(int headDir) {
         this.headDir = headDir;
     }
 
-    public static MainState load(Path directory) throws IOException {
+    public static MainState load(Path directory, Consumer<Exception> callback) throws IOException {
         Files.createDirectories(directory);
-        Path f = directory.resolve("main.state");
+        Path mainState = directory.resolve(MAIN_STATE);
         try {
+            byte[] bytes = Files.readAllBytes(mainState);
             MainState state = null;
-            try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(Files.newInputStream(f)))) {
-                state = (MainState) in.readObject();
+            try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) {
+                state = (MainState) org.simantics.databoard.Files.readFile(bais, Bindings.getBindingUnchecked(MainState.class));
             }
+            
             while (true) {
-                Path last = directory.resolve(Integer.toString(state.headDir - 1));
+                Path latest = directory.resolve(Integer.toString(state.headDir - 1));
                 try {
-                    Path headState = last.resolve("head.state");
+                    Path headState = latest.resolve(HeadState.HEAD_STATE);
                     HeadState.validateHeadStateIntegrity(headState);
                     break;
                 } catch (InvalidHeadStateException e) {
                     e.printStackTrace();
                     state.headDir--;
-                    uncheckedDeleteAll(last);
+                    callback.accept(e);
+                } finally {
+                    cleanBaseDirectory(directory, latest, callback);
                 }
             }
             return state;
-        } catch(IOException i) {
-            return new MainState( findNewHeadState(directory) );
-        } catch(ClassNotFoundException c) {
-            throw new Error("MainState class not found", c);
+        } catch(Exception i) {
+            callback.accept(i);
+            int largest = -1;
+            Path latest = findNewHeadStateDir(directory, callback);
+            if (latest != null)
+                largest = safeParseInt(-1, latest.getFileName().toString());
+            // +1 because we want to return the next head version to use,
+            // not the latest existing version.
+            largest++;
+            MainState state = new MainState( largest );
+            cleanBaseDirectory(directory, latest, callback);
+            return state;
         } finally {
-            if (Files.exists(f)) {
-                Files.delete(f);
+            if (Files.exists(mainState)) {
+                Files.delete(mainState);
             }
         }
     }
 
     public void save(Path directory) throws IOException {
-        Path f = directory.resolve("main.state");
-        try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(Files.newOutputStream(f)))) {
-            out.writeObject(this);
+        Path f = directory.resolve(MAIN_STATE);
+        BinaryMemory rf = new BinaryMemory(4096);
+        try {
+            MutableVariant v = new MutableVariant(Bindings.getBindingUnchecked(MainState.class), this);
+            Serializer s = Bindings.getSerializerUnchecked( Bindings.VARIANT );
+            s.serialize(rf, v);
+        } finally {
+            rf.close();
+        }
+        byte[] bytes = rf.toByteBuffer().array();
+        try (OutputStream out = Files.newOutputStream(f)) {
+            out.write(bytes);
         }
         FileIO.syncPath(f);
     }
@@ -78,13 +105,13 @@ public class MainState implements Serializable {
     }
 
     /**
-     * TODO> shouldn't do two things in the same function, this does both head.state search and directory cleanup
      *  
      * @param directory
+     * @param callback 
      * @return
      * @throws IOException
      */
-    private static int findNewHeadState(Path directory) throws IOException {
+    private static Path findNewHeadStateDir(Path directory, Consumer<Exception> callback) throws IOException {
         try (Stream<Path> s = Files.walk(directory, 1)) {
             List<Path> reverseSortedPaths = s
             .filter(p -> !p.equals(directory) && isInteger(p) && Files.isDirectory(p))
@@ -94,25 +121,19 @@ public class MainState implements Serializable {
                 return Integer.compare(p2Name, p1Name);
             }).collect(Collectors.toList());
 
-            int largest = -1;
+            Path latest = null;
             for (Path last : reverseSortedPaths) {
-                Path headState = last.resolve("head.state");
-                if (Files.exists(headState)) {
-                    try {
-                        HeadState.validateHeadStateIntegrity(headState);
-                        largest = safeParseInt(-1, last.getFileName().toString());
-                        break;
-                    } catch (IOException | InvalidHeadStateException e) {
-                        e.printStackTrace();
-                        uncheckedDeleteAll(last);
-                    }
-                } else {
-                    uncheckedDeleteAll(last);
+                Path headState = last.resolve(HeadState.HEAD_STATE);
+                try {
+                    HeadState.validateHeadStateIntegrity(headState);
+                    latest = last;
+                    break;
+                } catch (IOException | InvalidHeadStateException e) {
+                    // Cleanup is done in {@link cleanBaseDirectory} method
+                    callback.accept(e);
                 }
             }
-            // +1 because we want to return the next head version to use,
-            // not the latest existing version.
-            return largest + 1;
+            return latest;
         }
     }
 
@@ -124,6 +145,30 @@ public class MainState implements Serializable {
         }
     }
 
+    private static void cleanBaseDirectory(Path directory, Path latest, Consumer<Exception> callback) throws IOException {
+        try (Stream<Path> s = Files.walk(directory, 1)) {
+            List<Path> reverseSortedPaths = s
+            .filter(p -> !p.equals(directory) && isInteger(p) && Files.isDirectory(p))
+            .sorted((p1, p2) -> {
+                int p1Name = Integer.parseInt(p1.getFileName().toString()); 
+                int p2Name = Integer.parseInt(p2.getFileName().toString());
+                return Integer.compare(p2Name, p1Name);
+            }).collect(Collectors.toList());
+            
+            for (Path p : reverseSortedPaths) {
+                if (!p.equals(latest)) {
+                    // this indicates that there is a possibility that index and vg's are out of sync
+                    // if we are able to find folders with higher number than the current head.state
+                    callback.accept(null);
+                    uncheckedDeleteAll(p);
+                } else {
+                    break;
+                }
+            }
+            
+        }
+    }
+
     private static void uncheckedDeleteAll(Path path) {
         try {
             FileUtils.deleteAll(path.toFile());
index 0d209b2b8d744a4d442924179ddece20a5d1a1b2..86dfdd435122036d6aaf5b5c45042d7bed7f14f1 100644 (file)
@@ -3,9 +3,13 @@ package org.simantics.acorn;
 import java.io.IOException;
 import java.nio.file.Path;
 
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
+import org.simantics.db.exception.SDBException;
+
 public interface Persistable {
        
        void toFile(Path path) throws IOException ;
-       void fromFile(byte[] data);
+       void fromFile(byte[] data) throws IllegalAcornStateException, AcornAccessVerificationException;
        
 }
\ No newline at end of file
index 5ea0799d82fd116d2c9467a24a81a47cfeb1e6ac..3977ad73d0d86bb1e2a11dba50899ea3955494a2 100644 (file)
@@ -16,7 +16,9 @@ import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
+import org.simantics.acorn.AcornSessionManagerImpl;
 import org.simantics.acorn.GraphClientImpl2;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.backup.BackupException;
 import org.simantics.backup.IBackupProvider;
 import org.simantics.db.server.ProCoreException;
@@ -32,7 +34,12 @@ public class AcornBackupProvider implements IBackupProvider {
     private static final String IDENTIFIER = "AcornBackupProvider";
     private long trId = -1;
     private final Semaphore lock = new Semaphore(1);
+    private final GraphClientImpl2 client;
 
+    public AcornBackupProvider() {
+        this.client = AcornSessionManagerImpl.getInstance().getClient();
+    }
+    
     private static Path getAcornMetadataFile(Path dbFolder) {
         return dbFolder.getParent().resolve(IDENTIFIER);
     }
@@ -42,8 +49,7 @@ public class AcornBackupProvider implements IBackupProvider {
         try {
             if (trId != -1)
                 throw new IllegalStateException(this + " backup provider is already locked");
-            trId = GraphClientImpl2.getInstance().askWriteTransaction(-1)
-                    .getTransactionId();
+            trId = client.askWriteTransaction(-1).getTransactionId();
         } catch (ProCoreException e) {
             e.printStackTrace();
         }
@@ -55,7 +61,6 @@ public class AcornBackupProvider implements IBackupProvider {
         try {
             lock.acquire();
 
-            GraphClientImpl2 client = GraphClientImpl2.getInstance();
             client.makeSnapshot(true);
 
             Path dbDir = client.getDbFolder();
@@ -79,7 +84,7 @@ public class AcornBackupProvider implements IBackupProvider {
             throw new BackupException("Failed to lock Acorn for backup.", e);
         } catch (NumberFormatException e) {
             throw new BackupException("Failed to read Acorn head state file.", e);
-        } catch (IOException e) {
+        } catch (IllegalAcornStateException | IOException e) {
             throw new BackupException("I/O problem during Acorn backup.", e);
         } finally {
             if (releaseLock)
@@ -92,7 +97,7 @@ public class AcornBackupProvider implements IBackupProvider {
         try {
             if (trId == -1)
                 throw new BackupException(this + " backup provider is not locked");
-            GraphClientImpl2.getInstance().endTransaction(trId);
+            client.endTransaction(trId);
             trId = -1;
         } catch (ProCoreException e) {
             throw new BackupException(e);
@@ -105,7 +110,7 @@ public class AcornBackupProvider implements IBackupProvider {
             // 1. Resolve initial backup restore target.
             // This can be DB directory directly or a temporary directory that
             // will replace the DB directory.
-            Path dbRoot = GraphClientImpl2.getInstance().getDbFolder();
+            Path dbRoot = client.getDbFolder();
             Path restorePath = dbRoot;
             if (!Files.exists(dbRoot, LinkOption.NOFOLLOW_LINKS)) {
                 Files.createDirectories(dbRoot);
index f623d587f8d745907a86edf18fd1977fb5bfc894..51241728d16438278f1be4808404a0bc5c2754ef 100644 (file)
@@ -16,6 +16,8 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.Arrays;
 
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.acorn.internal.ClusterChange;
 import org.simantics.acorn.internal.ClusterStream;
 import org.simantics.acorn.internal.ClusterSupport2;
@@ -571,8 +573,11 @@ final public class ClusterBig extends ClusterImpl {
         try {
             return resourceTable.getValue(valueTable, resourceIndex);
         } catch (ExternalValueException e) {
-               return clusterSupport.impl.getResourceFile(clusterUID.asBytes(), resourceIndex);
-//            return support.getValueEx(resourceIndex, clusterUID.second);
+            try {
+                return clusterSupport.impl.getResourceFile(clusterUID.asBytes(), resourceIndex);
+            } catch (AcornAccessVerificationException | IllegalAcornStateException e1) {
+                throw new DatabaseException(e1);
+            }
         }
     }
     @Override
index 726071dbecd3c5d5521ba457481dfffc83efaa43..b84d4d51fe84fef82e1dc1f8a63fdb817cf3c82b 100644 (file)
@@ -16,15 +16,16 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.Arrays;
 
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.acorn.internal.ClusterChange;
 import org.simantics.acorn.internal.ClusterStream;
 import org.simantics.acorn.internal.ClusterSupport2;
 import org.simantics.acorn.internal.DebugPolicy;
 import org.simantics.db.Resource;
+import org.simantics.db.common.utils.Logger;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.exception.ExternalValueException;
 import org.simantics.db.exception.ValidationException;
-import org.simantics.db.impl.ClusterBase;
 import org.simantics.db.impl.ClusterI;
 import org.simantics.db.impl.ClusterSupport;
 import org.simantics.db.impl.ClusterTraitsBase;
@@ -708,8 +709,7 @@ final public class ClusterSmall extends ClusterImpl {
         }
     }
     @Override
-    public byte[] getValue(int resourceKey, ClusterSupport support)
-    throws DatabaseException {
+    public byte[] getValue(int resourceKey, ClusterSupport support) throws DatabaseException {
         if (DEBUG)
             System.out.println("ClusterSmall.getValue " + resourceKey);
         int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(resourceKey);
@@ -838,12 +838,11 @@ final public class ClusterSmall extends ClusterImpl {
         return resourceTable.getUsedSize();
     }
 
-    public int getNumberOfResources() {
-        
-        if(proxy) throw new IllegalStateException();
+    public int getNumberOfResources() throws IllegalAcornStateException {
+        if(proxy)
+            throw new IllegalAcornStateException("proxy == true for " + clusterId);
         
         return resourceTable.getUsedSize();
-        
     }
 
     @Override
@@ -1134,7 +1133,13 @@ final public class ClusterSmall extends ClusterImpl {
             });
             return "ClusterSmall[" + getClusterUID() + " - " + getClusterId() + " - " + getNumberOfResources() + " - " + foreignTable.getResourceHashMap().size() + " - " + set.size() + "]";
         } catch (DatabaseException e) {
-            return "ClusterSmall[" + getNumberOfResources() + "]";
+            try {
+                return "ClusterSmall[" + getNumberOfResources() + "]";
+            } catch (IllegalAcornStateException e1) {
+                Logger.defaultLogError(e1);
+                e1.printStackTrace();
+                return "An exception occured!!";
+            }
         }
     }
     
diff --git a/bundles/org.simantics.acorn/src/org/simantics/acorn/exception/AcornAccessVerificationException.java b/bundles/org.simantics.acorn/src/org/simantics/acorn/exception/AcornAccessVerificationException.java
new file mode 100644 (file)
index 0000000..6269a60
--- /dev/null
@@ -0,0 +1,20 @@
+package org.simantics.acorn.exception;
+
+import org.simantics.db.exception.SDBException;
+
+public class AcornAccessVerificationException extends SDBException {
+
+    private static final long serialVersionUID = 6601855907356895356L;
+
+    public AcornAccessVerificationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public AcornAccessVerificationException(String message) {
+        super(message);
+    }
+
+    public AcornAccessVerificationException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/bundles/org.simantics.acorn/src/org/simantics/acorn/exception/IllegalAcornStateException.java b/bundles/org.simantics.acorn/src/org/simantics/acorn/exception/IllegalAcornStateException.java
new file mode 100644 (file)
index 0000000..8228d59
--- /dev/null
@@ -0,0 +1,21 @@
+package org.simantics.acorn.exception;
+
+import org.simantics.db.exception.SDBException;
+
+public class IllegalAcornStateException extends SDBException {
+
+    private static final long serialVersionUID = -8255505454138490120L;
+
+    public IllegalAcornStateException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public IllegalAcornStateException(String message) {
+        super(message);
+    }
+
+    public IllegalAcornStateException(Throwable cause) {
+        super(cause);
+    }
+
+}
index 7cd007ace0f8918a1a191c8fa7ca9abfbff4e392..b1b1e8365f22bd8da329284a344639add33093cd 100644 (file)
@@ -8,6 +8,8 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
 
 import org.simantics.acorn.ClusterManager;
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.db.Session;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.impl.ClusterBase;
@@ -82,7 +84,11 @@ public class ClusterSupport2 implements ClusterSupport, IClusterTable {
        
        @Override
        public int getClusterKeyByClusterUIDOrMake(ClusterUID clusterUID) {
-               return impl.getClusterKeyByClusterUIDOrMakeWithoutMutex(clusterUID);
+               try {
+            return impl.getClusterKeyByClusterUIDOrMakeWithoutMutex(clusterUID);
+        } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
+            throw new RuntimeException(e);
+        }
        }
        
     @Override
@@ -185,14 +191,16 @@ public class ClusterSupport2 implements ClusterSupport, IClusterTable {
         }
     }
 
-    public ResourceSegment getResourceSegment(int resourceIndex, ClusterUID clusterUID, long offset, short size)
-    throws DatabaseException {
+    public ResourceSegment getResourceSegment(int resourceIndex, ClusterUID clusterUID, long offset, short size) throws DatabaseException {
         if (DEBUG)
             System.out.println("DEBUG: getResourceSegment ri=" + resourceIndex + " cid=" + clusterUID + " offset=" + offset + " size=" + size);
         
-        org.simantics.db.Database.Session.ResourceSegment t = impl.getResourceSegment(clusterUID.asBytes(), resourceIndex, offset, size);
-        return new ResourceSegment(t.getValueSize(), t.getSegment());
-        
+        try {
+            org.simantics.db.Database.Session.ResourceSegment t = impl.getResourceSegment(clusterUID.asBytes(), resourceIndex, offset, size);
+            return new ResourceSegment(t.getValueSize(), t.getSegment());
+        } catch (AcornAccessVerificationException | IllegalAcornStateException e) {
+            throw new DatabaseException(e);
+        }
     }
     
     protected byte[] getValueBig(ClusterBase cluster, int resourceIndex, int offset, int length) throws DatabaseException {
@@ -202,8 +210,11 @@ public class ClusterSupport2 implements ClusterSupport, IClusterTable {
        
        ClusterUID clusterUID = cluster.clusterUID;
        
-       return impl.getResourceFile(clusterUID.asBytes(), resourceIndex);
-       
+       try {
+            return impl.getResourceFile(clusterUID.asBytes(), resourceIndex);
+        } catch (AcornAccessVerificationException | IllegalAcornStateException e) {
+            throw new DatabaseException(e);
+        }
     }
 
     protected InputStream getValueStreamBig(ClusterBase cluster, final int resourceIndex, int offset, int length) throws DatabaseException {
@@ -247,7 +258,8 @@ public class ClusterSupport2 implements ClusterSupport, IClusterTable {
                @Override
                public int read() throws IOException {
 
-                       if(left <= 0) throw new IllegalStateException();
+                       if(left <= 0)
+                           throw new IOException("left <= 0 for " + _s);
 
                        if(offset == _s.bytes.length) {
                                short slen = (short)Math.min(left, IMAX);
index 0044d72d83b3d92736834ecf2a5bd9c00c43e18f..d4381aeca4e9610f1ee4e9fdf138e3f4cea1f99c 100644 (file)
@@ -2,7 +2,7 @@ package org.simantics.acorn.internal;
 
 import org.simantics.acorn.ClusterManager;
 import org.simantics.acorn.cluster.ClusterImpl;
-import org.simantics.acorn.lru.CachingClusterSupport;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.acorn.lru.ClusterUpdateOperation;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.impl.ClusterSupport;
@@ -76,7 +76,7 @@ public class ClusterUpdateProcessor extends ClusterUpdateProcessorBase {
 
        }
 
-       public ClusterImpl process(ClusterImpl cluster) {
+       public ClusterImpl process(ClusterImpl cluster) throws IllegalAcornStateException {
                this.cluster = cluster;
                process();
                info.finish();
index 7ce8673cbab9f9530633100ba4f7388a8d27e758..61a8a8a9d2578dd2217844d8cee6dff01fdd3c04 100644 (file)
@@ -1,6 +1,7 @@
 package org.simantics.acorn.internal;
 
 import org.simantics.acorn.cluster.ClusterImpl;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.acorn.lru.ClusterUpdateOperation;
 import org.simantics.db.impl.ClusterSupport;
 
@@ -16,7 +17,7 @@ public class ClusterUpdateProcessor2 extends ClusterUpdateProcessorBase2 {
                this.info = info;
        }
 
-       public void process(ClusterImpl cluster) {
+       public void process(ClusterImpl cluster) throws IllegalAcornStateException {
                this.cluster = cluster;
                process();
                info.finish();
index e0e733c1ef54bb4996c03ea42f1f4bd69cdaf61b..cd8130d9c51357902b2cea7ef3a2f9be2117f2a8 100644 (file)
@@ -5,6 +5,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import org.simantics.acorn.ClusterManager;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.acorn.internal.ClusterStream.ClusterEnum;
 import org.simantics.acorn.internal.ClusterStream.Data;
 import org.simantics.acorn.internal.ClusterStream.StmEnum;
@@ -26,7 +27,7 @@ abstract public class ClusterUpdateProcessorBase {
        
        final Map<ClusterUID, Integer> clusterKeyCache = new HashMap<ClusterUID, Integer>();
        
-       public int getResourceKey(ClusterUID uid, int index) {
+       public int getResourceKey(ClusterUID uid, int index) throws IllegalAcornStateException {
                Integer match = clusterKeyCache.get(uid);
                if(match != null) return match+index;
                int key = manager.getResourceKeyWitoutMutex(uid, 0);
@@ -192,7 +193,7 @@ abstract public class ClusterUpdateProcessorBase {
        int lows[] = new int[2];
        int foreignRefs[] = new int[2];
        
-       private void processStatement(int op, StmEnum stmEnum, ClusterEnum p, ClusterEnum o) {
+       private void processStatement(int op, StmEnum stmEnum, ClusterEnum p, ClusterEnum o) throws IllegalAcornStateException {
 
                int curPos = pos-1-24;
                
@@ -307,7 +308,7 @@ abstract public class ClusterUpdateProcessorBase {
                
        }
 
-       public void process() {
+       public void process() throws IllegalAcornStateException {
                
                foreignPos = 0;
 
index e821b46eb10eae6871ee9b3c3de5fb8c135e0a26..502729c0bab20982ab82100038898dc815e47be5 100644 (file)
@@ -1,5 +1,6 @@
 package org.simantics.acorn.internal;
 
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.db.service.Bytes;
 import org.simantics.db.service.ClusterUID;
 
@@ -35,7 +36,7 @@ public abstract class ClusterUpdateProcessorBase2 {
                pos+=4;
        }
 
-       public void process() {
+       public void process() throws IllegalAcornStateException {
                
                while(pos < len) {
                
@@ -50,12 +51,10 @@ public abstract class ClusterUpdateProcessorBase2 {
                                processUndoValue(op);
                                break;
                        default:
-                               throw new IllegalStateException();
+                               throw new IllegalAcornStateException("Can not process cluster " + uid);
                                
                        }
-                       
                }
-               
        }
        
        abstract void setImmutable(boolean value);
index d545e51adb02d9d1633e149df36cd9dc9b9be7ab..8b3e4f066a4e53a6033bc4c9fc8892aacee3f6eb 100644 (file)
@@ -5,6 +5,8 @@ import java.util.Arrays;
 import java.util.List;
 
 import org.simantics.acorn.ClusterManager;
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.acorn.lru.ClusterChangeSet;
 import org.simantics.acorn.lru.ClusterStreamChunk;
 import org.simantics.acorn.lru.ClusterChangeSet.Entry;
@@ -28,7 +30,7 @@ public class UndoClusterUpdateProcessor extends ClusterUpdateProcessorBase {
                this.ccs = ccs;
        }
        
-       private static byte[] readOperation(ClusterManager manager, ClusterStreamChunk chunk, ClusterChangeSet ccs) {
+       private static byte[] readOperation(ClusterManager manager, ClusterStreamChunk chunk, ClusterChangeSet ccs) throws AcornAccessVerificationException, IllegalAcornStateException {
                
 //             ClusterStreamChunk chunk;
 //             manager.streamLRU.acquireMutex();
index 12351a5194c3b07a17845cf8cb7a06f8d8fb6dd2..a730e136d3b8bce4c6bd18b922fb3344a0285d53 100644 (file)
@@ -4,6 +4,8 @@ import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
 
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.db.service.Bytes;
 import org.simantics.utils.datastructures.Pair;
 
@@ -15,13 +17,13 @@ public class ChangeSetInfo extends LRUObject<Long, ChangeSetInfo> {
        private ArrayList<String> clusterChangeSetIds;
        
        // Stub
-       public ChangeSetInfo(LRU<Long, ChangeSetInfo> LRU, Path readDir, Long revision, int offset, int length) {
+       public ChangeSetInfo(LRU<Long, ChangeSetInfo> LRU, Path readDir, Long revision, int offset, int length) throws AcornAccessVerificationException {
                super(LRU, revision, readDir, "clusterStream", offset, length, false, false);
                LRU.map(this);
        }
        
        // New
-       public ChangeSetInfo(LRU<Long, ChangeSetInfo> LRU, Long revision, byte[] bytes, ArrayList<String> clusterChangeSetIds) {
+       public ChangeSetInfo(LRU<Long, ChangeSetInfo> LRU, Long revision, byte[] bytes, ArrayList<String> clusterChangeSetIds) throws AcornAccessVerificationException {
                super(LRU, revision, LRU.getDirectory(), "clusterStream", true, true);
                this.metadataBytes = bytes;
                this.metadataBytes = bytes;
@@ -29,19 +31,17 @@ public class ChangeSetInfo extends LRUObject<Long, ChangeSetInfo> {
                LRU.insert(this, accessTime);
        }
        
-       public ArrayList<String> getCSSIds() {
+       public ArrayList<String> getCSSIds() throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
                return clusterChangeSetIds;
        }
        
-       public byte[] getMetadataBytes() {
-               
-               if(VERIFY) verifyAccess();
+       public byte[] getMetadataBytes() throws AcornAccessVerificationException, IllegalAcornStateException {
+               if(VERIFY)
+                   verifyAccess();
                
                makeResident();
-               
                return metadataBytes;
-               
        }
        
        private static void writeLE(TByteArrayList bytes, int value) {
index d0f3013d082ff6bea3aa8f3748be372d2da504a6..cfe5c1357111a07c52de61887541bc6b49cc8933 100644 (file)
@@ -3,6 +3,8 @@ package org.simantics.acorn.lru;
 import java.util.ArrayList;
 
 import org.simantics.acorn.ClusterManager;
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.acorn.internal.Change;
 import org.simantics.acorn.internal.ClusterChange;
 import org.simantics.db.procore.cluster.ClusterTraits;
@@ -40,9 +42,9 @@ public class ClusterChangeSet {
                        this.newValue = null;
                }
 
-               public Entry(int subject, boolean oldValueEx, byte[] oldValue, byte[] newValue) {
+               public Entry(int subject, boolean oldValueEx, byte[] oldValue, byte[] newValue) throws IllegalAcornStateException {
                        if(oldValue == null && newValue == null)
-                               throw new IllegalStateException();
+                               throw new IllegalAcornStateException("oldValue == null && newValue == null");
                        this.type = Type.VALUE;
                        this.subject = (short)(subject & 0xFFF);
                        this.predicate = 0;
@@ -54,7 +56,7 @@ public class ClusterChangeSet {
                        this.newValue = newValue;
                }
                
-               public void process(ClusterManager clusters, ClusterChange cs, int clusterKey) {
+               public void process(ClusterManager clusters, ClusterChange cs, int clusterKey) throws AcornAccessVerificationException {
                        
                        Entry e = this;
                        
@@ -113,7 +115,7 @@ public class ClusterChangeSet {
                chunkOffset = Integer.parseInt(ss[1]);
        }
        
-       public ClusterStreamChunk getChunk(ClusterManager manager) {
+       public ClusterStreamChunk getChunk(ClusterManager manager) throws AcornAccessVerificationException {
                return manager.streamLRU.get(chunkKey);
        }
 
index 1cd5822674ab4b14518707bc071ee85a2056d3d9..57dfe9f41442c0a327012e5f98efe02145bf2cba 100644 (file)
@@ -8,12 +8,15 @@ import org.simantics.acorn.ClusterManager;
 import org.simantics.acorn.Persistable;
 import org.simantics.acorn.cluster.ClusterImpl;
 import org.simantics.acorn.cluster.ClusterSmall;
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.acorn.cluster.ClusterImpl.ClusterTables;
 import org.simantics.acorn.internal.ClusterSupport2;
 import org.simantics.compressions.CompressionCodec;
 import org.simantics.compressions.Compressions;
 import org.simantics.db.ClusterCreator;
 import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.SDBException;
 import org.simantics.db.service.Bytes;
 import org.simantics.db.service.ClusterUID;
 import org.simantics.utils.datastructures.Pair;
@@ -28,7 +31,7 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
        public static final String COMPRESSION = "LZ4";
        
        // Stub
-       public ClusterInfo(ClusterManager manager, LRU<ClusterUID, ClusterInfo> LRU, Path readDirectory, ClusterUID uid, int offset, int length) {
+       public ClusterInfo(ClusterManager manager, LRU<ClusterUID, ClusterInfo> LRU, Path readDirectory, ClusterUID uid, int offset, int length) throws AcornAccessVerificationException {
                super(LRU, uid, readDirectory, uid.toString() + ".cluster", offset, length, false, false);
                this.manager = manager;
                this.cluster = null;
@@ -36,7 +39,7 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
        }
        
        // New
-       public ClusterInfo(ClusterManager manager, LRU<ClusterUID, ClusterInfo> LRU, ClusterImpl cluster) {
+       public ClusterInfo(ClusterManager manager, LRU<ClusterUID, ClusterInfo> LRU, ClusterImpl cluster) throws AcornAccessVerificationException, IllegalAcornStateException {
                super(LRU, cluster.getClusterUID(), LRU.getDirectory(), cluster.getClusterUID().toString() + ".cluster", true, true);
                this.manager = manager;
                this.cluster = cluster;
@@ -44,7 +47,7 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
                LRU.swap(getKey());
        }
        
-       public <T> T clone(ClusterUID uid, ClusterCreator creator) throws DatabaseException {
+       public <T> T clone(ClusterUID uid, ClusterCreator creator) throws IOException, AcornAccessVerificationException, IllegalAcornStateException {
                
                // Updates have been ensured at this point
                        
@@ -56,9 +59,9 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
                                return creator.create(uid, tables.bytes, tables.ints, tables.longs); 
                        }
                } catch (IOException e) {
-                       throw new DatabaseException(e);
+                       throw e;
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
                        releaseMutex();
                }
@@ -80,9 +83,9 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
                        }
 
                } catch (IOException e) {
-                       throw new DatabaseException(e);
+                       throw e;
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
                        releaseMutex();
                }
@@ -170,10 +173,8 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
        }
 
        @Override
-       protected Pair<byte[],Integer> toBytes() {
-               
+       protected Pair<byte[],Integer> toBytes() throws IllegalAcornStateException {
                try {
-
                        byte[] raw = null;
                        
                        if(cluster instanceof ClusterSmall) {
@@ -215,7 +216,7 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
                        return Pair.make(result, compressedSize+4);
 
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
                        release();
                }
@@ -233,7 +234,7 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
                return "cluster";
        }
        
-       public void scheduleUpdate() {
+       public void scheduleUpdate() throws AcornAccessVerificationException {
 
                if(VERIFY) verifyAccess();
 
@@ -243,10 +244,8 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
 
        }
        
-       public ClusterImpl getForUpdate() {
-
+       public ClusterImpl getForUpdate() throws SDBException {
                try {
-                       
                        acquireMutex();
 
                        assert(updateState != null);
@@ -255,18 +254,16 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
                        setDirty(true);
                        updateState.beginUpdate();
                        return cluster;
-                       
+               } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
+                   throw e;
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
-                       
                        releaseMutex();
-                       
                }
-
        }
        
-       public void update(ClusterImpl clu) {
+       public void update(ClusterImpl clu) throws AcornAccessVerificationException, IllegalAcornStateException {
                
                if(VERIFY) verifyAccess();
                
@@ -278,7 +275,7 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
 
        }
        
-       public ClusterImpl getCluster() {
+       public ClusterImpl getCluster() throws AcornAccessVerificationException, IllegalAcornStateException {
 
                if(VERIFY) verifyAccess();
 
@@ -289,7 +286,7 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
        }
        
        @Override
-       public boolean canBePersisted() {
+       public boolean canBePersisted() throws AcornAccessVerificationException {
                
                if(VERIFY) verifyAccess();
 
@@ -302,7 +299,7 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
                
        }
 
-       private ClusterUpdateState getUpdateState() {
+       private ClusterUpdateState getUpdateState() throws AcornAccessVerificationException {
                
                if(VERIFY) verifyAccess();
                
@@ -310,13 +307,13 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
                
        }
 
-       private ClusterUpdateState getUpdateStateWithoutMutex() {
+       private ClusterUpdateState getUpdateStateWithoutMutex() throws IllegalAcornStateException {
                
                try {
                        acquireMutex();
                        return getUpdateState();
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
                        releaseMutex();
                }
@@ -326,7 +323,7 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
        /*
         * This method blocks - no locks here
         */
-       public void waitForUpdates() {
+       public void waitForUpdates() throws IllegalAcornStateException {
                
                ClusterUpdateState state = getUpdateStateWithoutMutex();
                if(state != null) {
@@ -335,7 +332,6 @@ public class ClusterInfo extends LRUObject<ClusterUID, ClusterInfo> implements P
                        long duration = System.nanoTime() - start;
                        System.err.println("Wait updates to cluster " + getKey() + " for " + (1e-6 * duration) + "ms.");
                }
-               
        }
        
        @Override
index 1f0db54354184c89af52d102fe622cb88d9c9926..6b5252161a814668411ae8a60d2bc5d5d0a0a643 100644 (file)
@@ -6,6 +6,8 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import org.simantics.acorn.ClusterManager;
 import org.simantics.acorn.cluster.ClusterImpl;
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.acorn.internal.BijectionMap;
 import org.simantics.db.common.utils.Logger;
 import org.simantics.db.exception.ClusterDoesNotExistException;
@@ -19,18 +21,14 @@ import gnu.trove.TIntIntHashMap;
 public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
 
        final private BijectionMap<ClusterUID, Integer> clusterMapping = new BijectionMap<ClusterUID, Integer>();
-       final private ClusterManager manager;
        
        public ClusterLRU(ClusterManager manager, String identifier, Path writeDir) {
-               
-               super(identifier, writeDir);
-               this.manager = manager;
+               super(manager, identifier, writeDir);
                
                clusterMapping.map(ClusterUID.make(0,2), clusterMapping.size() + 1);
-
        }
 
-       public ClusterInfo getOrCreate(ClusterUID uid, boolean makeIfNull) {
+       public ClusterInfo getOrCreate(ClusterUID uid, boolean makeIfNull) throws IllegalAcornStateException, AcornAccessVerificationException {
                
                try {
                        
@@ -40,7 +38,7 @@ public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
 
                        if (info == null) {
                                
-                               if(!makeIfNull) throw new IllegalStateException("Asked for an existing cluster " + uid + " that was not found.");
+                               if(!makeIfNull) throw new IllegalAcornStateException("Asked for an existing cluster " + uid + " that was not found.");
 
                                Integer clusterKey = clusterMapping.getRight(uid);
                                if (clusterKey == null) {
@@ -54,9 +52,10 @@ public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
                        }
 
                        return info;
-                       
+               } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
+                   throw e;
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
                        
                        releaseMutex();
@@ -68,16 +67,15 @@ public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
        /*
         * This method waits - we have no locks here
         */
-       public void ensureUpdates(ClusterUID uid) throws DatabaseException {
+       public void ensureUpdates(ClusterUID uid) throws ClusterDoesNotExistException, AcornAccessVerificationException, IllegalAcornStateException {
 
                ClusterInfo info = getWithoutMutex(uid);
                if(info == null)
                    throw new ClusterDoesNotExistException("Asked a cluster which does not exist: " + uid);
                info.waitForUpdates();
-               
        }
 
-       public ClusterInfo get(ClusterUID uid, boolean makeIfNull, boolean ensureUpdates) throws DatabaseException {
+       public ClusterInfo get(ClusterUID uid, boolean makeIfNull, boolean ensureUpdates) throws AcornAccessVerificationException, IllegalAcornStateException {
 
                if (ensureUpdates) {
                    try {
@@ -86,19 +84,18 @@ public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
                        if (makeIfNull) {
                            Logger.defaultLogError("For debug purposes, creating cluster which does not exist", e);
                        } else {
-                           throw e;
+                           throw new IllegalAcornStateException(e);
                        }
                    }
                }
                return getOrCreate(uid, makeIfNull);
        }
        
-       public ClusterInfo get(ClusterUID uid, boolean makeIfNull) throws DatabaseException {
+       public ClusterInfo get(ClusterUID uid, boolean makeIfNull) throws AcornAccessVerificationException, IllegalAcornStateException {
                return get(uid, makeIfNull, true);
-               
        }
 
-       public int getResourceKey(ClusterUID uid, int index) {
+       public int getResourceKey(ClusterUID uid, int index) throws AcornAccessVerificationException {
 
                if(VERIFY) verifyAccess();
 
@@ -111,20 +108,19 @@ public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
 
        }
 
-       public int getResourceKeyWithoutMutex(ClusterUID uid, int index) {
+       public int getResourceKeyWithoutMutex(ClusterUID uid, int index) throws IllegalAcornStateException {
                
                acquireMutex();
                try {
                        return getResourceKey(uid, index);
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
                        releaseMutex();
                }
-               
        }
 
-       public int createClusterKeyByClusterUID(ClusterUID uid) {
+       public int createClusterKeyByClusterUID(ClusterUID uid) throws AcornAccessVerificationException {
                
                if(VERIFY) verifyAccess();
                
@@ -137,7 +133,7 @@ public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
                
        }
 
-       public ClusterBase getClusterByClusterUIDOrMake(ClusterUID uid) throws DatabaseException {
+       public ClusterBase getClusterByClusterUIDOrMake(ClusterUID uid) throws AcornAccessVerificationException, IllegalAcornStateException {
                
                if(VERIFY) verifyAccess();
                
@@ -146,7 +142,7 @@ public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
                
        }
 
-       public int getClusterKeyByClusterUIDOrMake(ClusterUID clusterUID) {
+       public int getClusterKeyByClusterUIDOrMake(ClusterUID clusterUID) throws AcornAccessVerificationException {
 
                if(VERIFY) verifyAccess();
 
@@ -154,18 +150,20 @@ public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
                        
        }
        
-       public int getClusterKeyByClusterUIDOrMakeWithoutMutex(ClusterUID clusterUID) {
+       public int getClusterKeyByClusterUIDOrMakeWithoutMutex(ClusterUID clusterUID) throws IllegalAcornStateException, AcornAccessVerificationException {
                acquireMutex();
                try {
                        return getClusterKeyByClusterUIDOrMake(clusterUID);
+               } catch (AcornAccessVerificationException e) {
+            throw e;
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
                        releaseMutex();
                }
        }
 
-       public ClusterBase getClusterByClusterKey(int clusterKey) throws DatabaseException {
+       public ClusterBase getClusterByClusterKey(int clusterKey) throws AcornAccessVerificationException, IllegalAcornStateException {
                
                if(VERIFY) verifyAccess();
                
@@ -174,16 +172,16 @@ public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
                info.acquireMutex();
                try {
                        return info.getCluster();
+               } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
+                   throw e;
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
                        info.releaseMutex();
                }
-               
        }
 
-       public ClusterUID getClusterUIDByResourceKey(int resourceKey)
-                       throws DatabaseException {
+       public ClusterUID getClusterUIDByResourceKey(int resourceKey) throws AcornAccessVerificationException {
                
                if(VERIFY) verifyAccess();
                
@@ -192,24 +190,22 @@ public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
                
        }
        
-       public ClusterUID getClusterUIDByResourceKeyWithoutMutex(int resourceKey) throws DatabaseException {
+       public ClusterUID getClusterUIDByResourceKeyWithoutMutex(int resourceKey) throws IllegalAcornStateException, AcornAccessVerificationException {
                acquireMutex();
                try {
                        return getClusterUIDByResourceKey(resourceKey);
-               } catch (Throwable t) {
-                       throw new IllegalStateException(t);
                } finally {
                        releaseMutex();
                }
        }
 
        @SuppressWarnings("unchecked")
-       public <T extends ClusterI> T getClusterByClusterUIDOrMakeProxy(ClusterUID uid) throws DatabaseException {
+       public <T extends ClusterI> T getClusterByClusterUIDOrMakeProxy(ClusterUID uid) throws DatabaseException, AcornAccessVerificationException, IllegalAcornStateException {
                return (T) getClusterByClusterUIDOrMake(uid);
        }
 
        @SuppressWarnings("unchecked")
-       public <T extends ClusterI> T getClusterProxyByResourceKey(int resourceKey) throws DatabaseException {
+       public <T extends ClusterI> T getClusterProxyByResourceKey(int resourceKey) throws DatabaseException, AcornAccessVerificationException, IllegalAcornStateException {
                
                if(VERIFY) verifyAccess();
 
@@ -217,7 +213,7 @@ public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
                
        }
 
-       public int getClusterKeyByUID(long id1, long id2) throws DatabaseException {
+       public int getClusterKeyByUID(long id1, long id2) throws DatabaseException, AcornAccessVerificationException {
                
                if(VERIFY) verifyAccess();
 
@@ -225,17 +221,15 @@ public class ClusterLRU extends LRU<ClusterUID, ClusterInfo> {
                
        }
        
-       public int getClusterKeyByUIDWithoutMutex(long id1, long id2) throws DatabaseException {
-
+       public int getClusterKeyByUIDWithoutMutex(long id1, long id2) throws DatabaseException, IllegalAcornStateException {
                acquireMutex();
                try {
                        return getClusterKeyByClusterUIDOrMake(ClusterUID.make(id1, id2));
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
                        releaseMutex();
                }
-
        }
 
        
index 23cbfb1ce9cf2cbd1c8871e25dcc3216b2594aa0..57d6f6a04b5d387c2c0b31ca2fd6cafab845dd4c 100644 (file)
@@ -7,6 +7,8 @@ import java.util.ArrayList;
 
 import org.simantics.acorn.ClusterManager;
 import org.simantics.acorn.Persistable;
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.acorn.internal.ClusterChange;
 import org.simantics.acorn.internal.UndoClusterUpdateProcessor;
 import org.simantics.compressions.CompressionCodec;
@@ -31,14 +33,14 @@ public class ClusterStreamChunk extends LRUObject<String, ClusterStreamChunk> im
        public ArrayList<ClusterUpdateOperation> operations = new ArrayList<ClusterUpdateOperation>();
        
        // Stub
-       public ClusterStreamChunk(ClusterManager manager, LRU<String, ClusterStreamChunk> LRU, Path readDir, String id, int offset, int length) {
+       public ClusterStreamChunk(ClusterManager manager, LRU<String, ClusterStreamChunk> LRU, Path readDir, String id, int offset, int length) throws AcornAccessVerificationException {
                super(LRU, id, readDir, "clusterStream", offset, length, false, false);
                this.manager = manager;
                LRU.map(this);
        }
        
        // Creation
-       public ClusterStreamChunk(ClusterManager manager, LRU<String, ClusterStreamChunk> LRU, String id) {
+       public ClusterStreamChunk(ClusterManager manager, LRU<String, ClusterStreamChunk> LRU, String id) throws AcornAccessVerificationException {
                super(LRU, id, LRU.getDirectory(), "clusterStream", true, true);
                this.manager = manager;
                LRU.insert(this, accessTime);
@@ -51,8 +53,8 @@ public class ClusterStreamChunk extends LRUObject<String, ClusterStreamChunk> im
                makeResident(true);
 
                ClusterUpdateOperation op = operations.get(chunkOffset);
-               if(op == null) throw new IllegalStateException("Cluster Update Operation " + ccsId + " was not found.");
-               if(op.ccs == null) throw new IllegalStateException("Cluster ChangeSet " + ccsId + " was not found.");
+               if(op == null) throw new IllegalAcornStateException("Cluster Update Operation " + ccsId + " was not found.");
+               if(op.ccs == null) throw new IllegalAcornStateException("Cluster ChangeSet " + ccsId + " was not found.");
 
                UndoClusterUpdateProcessor proc = new UndoClusterUpdateProcessor(clusters, this, op.ccs);
                if(proc.version != ClusterChange.VERSION)
@@ -69,9 +71,9 @@ public class ClusterStreamChunk extends LRUObject<String, ClusterStreamChunk> im
                
        }
        
-       public void addOperation(ClusterUpdateOperation op) {
+       public void addOperation(ClusterUpdateOperation op) throws IllegalAcornStateException {
                if(committed)
-                       throw new IllegalStateException();
+                       throw new IllegalAcornStateException("Cannot add operation " + op + " to " + this + " if commited == true");
                operations.add(op);
                size += op.data.length;
 //             if(isCommitted()) {
@@ -93,7 +95,7 @@ public class ClusterStreamChunk extends LRUObject<String, ClusterStreamChunk> im
        }
        
        @Override
-       public boolean canBePersisted() {
+       public boolean canBePersisted() throws AcornAccessVerificationException {
                if(!super.canBePersisted()) return false;
                if(!isCommitted()) return false;
                for(ClusterUpdateOperation op : operations) {
@@ -213,7 +215,7 @@ public class ClusterStreamChunk extends LRUObject<String, ClusterStreamChunk> im
        private static StreamDecompressor decompressor = new StreamDecompressor();
        
        @Override
-       public void fromFile(byte[] data_) {
+       public void fromFile(byte[] data_) throws IllegalAcornStateException, AcornAccessVerificationException {
 
                try {
                        
@@ -271,17 +273,13 @@ public class ClusterStreamChunk extends LRUObject<String, ClusterStreamChunk> im
                                        }
 
                                }
-                               
                                operations.add(op);
-                               
                        }
-                       
                } catch (IOException e) {
-                       
-                       throw new IllegalStateException(e);
-                       
-               }
-               
+                       throw new IllegalAcornStateException(e);
+               } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
+            throw e;
+        }
        }
 
        @Override
index 40a44bc43bc17e85c1114b3bae21aee53bb6573d..c23821b7973c51b8e0a8828c7fc66b3e894c4d08 100644 (file)
@@ -2,6 +2,8 @@ package org.simantics.acorn.lru;
 
 import org.simantics.acorn.ClusterManager;
 import org.simantics.acorn.cluster.ClusterImpl;
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.acorn.internal.ClusterChange;
 import org.simantics.acorn.internal.ClusterChange2;
 import org.simantics.acorn.internal.ClusterUpdateProcessor;
@@ -21,7 +23,7 @@ final public class ClusterUpdateOperation {
        public ClusterChangeSet ccs;
        boolean finished = false;
 
-       public ClusterUpdateOperation(ClusterManager manager, byte[] data) {
+       public ClusterUpdateOperation(ClusterManager manager, byte[] data) throws IllegalAcornStateException, AcornAccessVerificationException {
                
                long cuid1 = Bytes.readLE8(data, 8);
                long cuid2 = Bytes.readLE8(data, 16);
@@ -30,20 +32,19 @@ final public class ClusterUpdateOperation {
                this.uid = ClusterUID.make(cuid1, cuid2);
                this.data = data;
                this.info = manager.clusterLRU.getOrCreate(uid, true);
-                               
        }
        
        public void finish() {
                finished = true;
        }
        
-       public void scheduled(String ccsInfoId) {
+       public void scheduled(String ccsInfoId) throws AcornAccessVerificationException, IllegalAcornStateException {
                ccs = new ClusterChangeSet(ccsInfoId, uid);
                chunk = ccs.getChunk(manager);
                manager.addIntoCurrentChangeSet(ccsInfoId);
        }
        
-       public void run() {
+       public void run() throws AcornAccessVerificationException, IllegalAcornStateException {
                ClusterUpdateOperation op = null;
                byte[] data = null;
                chunk.acquireMutex();
@@ -51,15 +52,13 @@ final public class ClusterUpdateOperation {
                        chunk.makeResident();
                        op = chunk.operations.get(ccs.chunkOffset);
                        data = op.data;
-               } catch (Throwable t) {
-                       throw new IllegalStateException(t);
                } finally {
                        chunk.releaseMutex();
                }
                op.runWithData(data);
        }
        
-       public void runWithData(byte[] data) {
+       public void runWithData(byte[] data) throws IllegalAcornStateException, AcornAccessVerificationException {
                
                try {
                        int version = Bytes.readLE4(data, 4);
@@ -74,12 +73,13 @@ final public class ClusterUpdateOperation {
                                processor.process(cluster);
                                manager.update(uid, cluster);
                        } else {
-                               throw new IllegalStateException();
+                               throw new IllegalAcornStateException("unsupported clusterChange version " + version);
                        }
+               } catch (IllegalAcornStateException | AcornAccessVerificationException e) {
+                   throw e;
                } catch (Throwable t) {
-                       t.printStackTrace();
+                       throw new IllegalAcornStateException(t);
                }
-               
        }
        
        @Override
index 660f245013b36bcf9879d90ed4af69de4d20a7cf..116464727c55cceb44500b740880c9912d1ca373 100644 (file)
@@ -2,8 +2,9 @@ package org.simantics.acorn.lru;
 
 import java.nio.file.Path;
 
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.db.Database.Session.ResourceSegment;
-import org.simantics.db.server.ProCoreException;
 import org.simantics.utils.datastructures.Pair;
 
 import gnu.trove.list.array.TByteArrayList;
@@ -13,38 +14,33 @@ public class FileInfo extends LRUObject<String, FileInfo> {
        private TByteArrayList bytes;
        
        // Stub
-       public FileInfo(LRU<String, FileInfo> LRU, Path readDir, String id, int offset, int length) {
+       public FileInfo(LRU<String, FileInfo> LRU, Path readDir, String id, int offset, int length) throws AcornAccessVerificationException {
                super(LRU, id, readDir, id.toString() + ".extFile", offset, length, false, false);
                LRU.map(this);
        }
        
        // New
-       public FileInfo(LRU<String, FileInfo> LRU, String id, int size) {
+       public FileInfo(LRU<String, FileInfo> LRU, String id, int size) throws AcornAccessVerificationException {
                super(LRU, id, LRU.getDirectory(), id.toString() + ".extFile", true, true);
                this.bytes = new TByteArrayList(size);
                LRU.insert(this, accessTime);
        }
 
-       public byte[] getResourceFile() {
+       public byte[] getResourceFile() throws AcornAccessVerificationException, IllegalAcornStateException {
                
                if(VERIFY) verifyAccess();
                
                makeResident();
                return bytes.toArray();
-
        }
        
        
-       public ResourceSegment getResourceSegment(final byte[] clusterUID,
-                       final int resourceIndex, final long segmentOffset, short segmentSize)
-                       throws ProCoreException {
+       public ResourceSegment getResourceSegment(final byte[] clusterUID, final int resourceIndex, final long segmentOffset, short segmentSize) throws AcornAccessVerificationException, IllegalAcornStateException {
 
                if(VERIFY) verifyAccess();
 
                makeResident();
-
                try {
-
                        int segSize = segmentSize;
                        if (segSize < 0)
                                segSize += 65536;
@@ -52,7 +48,6 @@ public class FileInfo extends LRUObject<String, FileInfo> {
                                segSize = Math.min(65535, bytes.size());
 
                        final long valueSize = bytes.size();
-
                        final byte[] segment = bytes.toArray((int) segmentOffset, segSize);
 
                        return new ResourceSegment() {
@@ -82,18 +77,12 @@ public class FileInfo extends LRUObject<String, FileInfo> {
                                        return clusterUID;
                                }
                        };
-
                } catch (Throwable t) {
-
-                       t.printStackTrace();
-
+                       throw new IllegalAcornStateException(t);
                }
-
-               throw new UnsupportedOperationException();
-
        }
        
-       public void updateData(byte[] newBytes, long offset, long pos, long size) {
+       public void updateData(byte[] newBytes, long offset, long pos, long size) throws AcornAccessVerificationException, IllegalAcornStateException {
 
                if(VERIFY) verifyAccess();
                makeResident();
index 508127db9f6f538718d13e20cc3d98de71b1662c..323d66d3df12ea34d2d429293801eeacfc95a23b 100644 (file)
@@ -12,7 +12,10 @@ import java.util.concurrent.Semaphore;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 
+import org.simantics.acorn.ClusterManager;
 import org.simantics.acorn.GraphClientImpl2;
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.db.common.utils.Logger;
 
 /*
@@ -39,8 +42,11 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
        private Thread mutexOwner;
        
        public Map<String, WriteRunnable> pending = new HashMap<String, WriteRunnable>();
+
+    protected final ClusterManager manager;
        
-       public LRU(String identifier, Path writeDir) {
+       public LRU(ClusterManager manager, String identifier, Path writeDir) {
+           this.manager = manager;
                this.identifier = identifier;
                this.writeDir = writeDir;
                resume();
@@ -50,19 +56,15 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
         * Public interface
         */
        
-       public void acquireMutex() {
-               
+       public void acquireMutex() throws IllegalAcornStateException {
                try {
-                       
                        while(!mutex.tryAcquire(3, TimeUnit.SECONDS)) {
                                System.err.println("Mutex is taking a long time to acquire - owner is " + mutexOwner);
                        }
-                               
                        if(VERIFY)
                                mutexOwner = Thread.currentThread();
-                               
                } catch (InterruptedException e) {
-                       throw new IllegalStateException(e);
+                       throw new IllegalAcornStateException(e);
                }
        }
        
@@ -90,7 +92,6 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
                        public Thread newThread(Runnable r) {
                                return new Thread(r, identifier + " File Writer");
                        }
-                       
                });
                if (GraphClientImpl2.DEBUG)
                    System.err.println("Resuming LRU writers " + writers);
@@ -100,12 +101,10 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
         * This method violates the synchronization order rule between LRU and MapVAlue
         * External synchronization is used to ensure correct operation
         */
-       public void persist(ArrayList<String> state) {
+       public void persist(ArrayList<String> state) throws IllegalAcornStateException {
        
                acquireMutex();
-               
                try {
-               
                        for (MapValue value : values()) {
                                value.acquireMutex();
                                // for debugging purposes
@@ -124,78 +123,69 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
                                try {
                                        // Record the value
                                        state.add(value.getStateKey());
-                               } catch (Throwable t) {
-                                       throw new IllegalStateException(t);
                                } finally {
                                        value.releaseMutex();
                                }
                        }
-                       
+               } catch (IllegalAcornStateException e) {
+                   throw e;
+               } catch (IOException e) {
+                   throw new IllegalAcornStateException("Unable to waitPending for " + this.identifier, e);
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                   throw new IllegalAcornStateException("Fatal error occured for " + this.identifier, t);
                } finally {
                        releaseMutex();
                }
-
        }
 
-       public MapValue getWithoutMutex(MapKey key) {
+       public MapValue getWithoutMutex(MapKey key) throws AcornAccessVerificationException, IllegalAcornStateException {
                
                acquireMutex();
                try {
                        return get(key);
-               } catch (Throwable t) {
-                       throw new IllegalStateException(t);
                } finally {
                        releaseMutex();
                }
-               
        }
 
-       public MapValue get(MapKey key) {
+       public MapValue get(MapKey key) throws AcornAccessVerificationException {
                
                if(VERIFY) verifyAccess();
                
                return map.get(key);
-               
        }
 
-       public void map(MapValue info) {
+       public void map(MapValue info) throws AcornAccessVerificationException {
                
                if(VERIFY) verifyAccess();
                
                map.put(info.getKey(), info);
-               
        }
 
-       public Collection<MapValue> values() {
+       public Collection<MapValue> values() throws AcornAccessVerificationException {
                
                if(VERIFY) verifyAccess();
                
                return map.values();
-               
        }
 
-       public boolean swapForced() {
+       public boolean swapForced() throws IllegalAcornStateException, AcornAccessVerificationException {
                
                acquireMutex();
                
                try {
                        return swap(0, 0, null);
-               } catch (Throwable t) {
-                       throw new IllegalStateException(t);
                } finally {
                        releaseMutex();
                }
                
        }
 
-       public boolean swap(long lifeTime, int targetSize) {
+       public boolean swap(long lifeTime, int targetSize) throws AcornAccessVerificationException, IllegalAcornStateException {
                
                if(VERIFY) verifyAccess();
 
                return swap(lifeTime, targetSize, null);
-               
        }
 
        /*
@@ -204,7 +194,6 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
        public void setWriteDir(Path dir) {
                
                this.writeDir = dir;
-               
        }
 
 
@@ -212,19 +201,18 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
         * Package access
         */
 
-       void insert(MapValue info, long accessTime) {
+       void insert(MapValue info, long accessTime) throws AcornAccessVerificationException {
                
                if(VERIFY) verifyAccess();
 
                map.put(info.getKey(), info);
                priorityQueue.put(accessTime, info.getKey());
-               
        }
 
        /*
         * We have access to ClusterLRU - try to refresh value if available
         */
-       boolean tryRefresh(MapValue info) {
+       boolean tryRefresh(MapValue info) throws AcornAccessVerificationException, IllegalAcornStateException {
 
                if(VERIFY) verifyAccess();
                
@@ -232,28 +220,20 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
                        return false;
 
                try {
-
                        priorityQueue.remove(info.getLastAccessTime());
                        info.accessed();
                        map.put(info.getKey(), info);
                        priorityQueue.put(info.getLastAccessTime(), info.getKey());
-                       
                        return true;
-
-               } catch (Throwable t) {
-                       throw new IllegalStateException(t);
                } finally {
-
                        info.releaseMutex();
-                       
                }
-               
        }
 
        /*
         * We have access to MapValue and no access to clusterLRU
         */
-       void refresh(MapValue info, boolean needMutex) {
+       void refresh(MapValue info, boolean needMutex) throws AcornAccessVerificationException, IllegalAcornStateException {
                
                if(VERIFY) {
                        if(!needMutex) verifyAccess();
@@ -270,38 +250,31 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
                        map.put(info.getKey(), info);
                        priorityQueue.put(info.getLastAccessTime(), info.getKey());
 
+               } catch (AcornAccessVerificationException e) {
+                   throw e;
                } catch (Throwable t) {
-                       throw new IllegalStateException(t);
+                       throw new IllegalAcornStateException(t);
                } finally {
-
                        if(needMutex)
                                releaseMutex();
-                       
                }
-               
        }
 
        /*
         * Private implementation
         */
 
-       public int size() {
-               
+       int size() throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
-
                return priorityQueue.size();
-               
        }
 
-       boolean swap(MapKey excluded) {
-               
+       boolean swap(MapKey excluded) throws AcornAccessVerificationException, IllegalAcornStateException {
                if(VERIFY) verifyAccess();
-
                return swap(swapTime, swapSize, excluded);
-               
        }
 
-       boolean swap(long lifeTime, int targetSize, MapKey excluded) {
+       boolean swap(long lifeTime, int targetSize, MapKey excluded) throws AcornAccessVerificationException, IllegalAcornStateException {
 
                if(VERIFY) verifyAccess();
 
@@ -309,29 +282,22 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
                if(valueToSwap != null) {
                        
                        if(valueToSwap.tryAcquireMutex()) {
-                               
                                try {
-                                       
                                        if(valueToSwap.canBePersisted()) {
                                                valueToSwap.persist();
                                                return true;
                                        }
-                                       
                                } catch (Throwable t) {
-                                       throw new IllegalStateException(t);
+                                       throw new IllegalAcornStateException(t);
                                } finally {
                                        valueToSwap.releaseMutex();
                                }
                        }
-                       
                }
-               
                return false;
-
        }
 
-       
-       private MapValue getValueToSwap1(long lifeTime, int targetSize, MapKey excluded) {
+       private MapValue getValueToSwap1(long lifeTime, int targetSize, MapKey excluded) throws AcornAccessVerificationException, IllegalAcornStateException {
 
                if(VERIFY) verifyAccess();
 
@@ -347,15 +313,12 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
                        }
                        
                        return map.get(key);
-                       
                }
-               
                return null;
-
        }
        
        
-       private MapValue getValueToSwap(long lifeTime, int targetSize, MapKey excluded) {
+       private MapValue getValueToSwap(long lifeTime, int targetSize, MapKey excluded) throws AcornAccessVerificationException, IllegalAcornStateException {
 
                if(VERIFY) verifyAccess();
 
@@ -368,29 +331,20 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
                        if(value.tryAcquireMutex()) {
 
                                try {
-                                       
                                        // This may lock the object
-                                       if(value.canBePersisted()) return value;
+                                       if(value.canBePersisted())
+                                           return value;
                                        // Insert back the value
                                        refresh(value, false);
-       
-                               } catch (Throwable t) {
-                                       throw new IllegalStateException(t);
                                } finally {
-                                       
                                        value.releaseMutex();
-                                       
                                }
-                               
                        }
-                       
                }
-               
                return null;
-               
        }
        
-       private long getSwapCandidate(long lifeTime, int targetSize) {
+       private long getSwapCandidate(long lifeTime, int targetSize) throws AcornAccessVerificationException {
                
                if(VERIFY) verifyAccess();
 
@@ -411,14 +365,13 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
         * Tries to persist this object. Can fail if the object cannot be persisted at this time.
         * 
         */
-       boolean persist(Object object_) {
+       boolean persist(Object object_) throws AcornAccessVerificationException {
                
                MapValue object = (MapValue)object_;
                
                if(VERIFY) object.verifyAccess();
                
                if(object.isDirty()) {
-
                        // It is possible that this just became unpersistable. Fail here in this case.
                        if(!object.canBePersisted()) {
                                return false;
@@ -447,21 +400,17 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
                        object.release();
                        object.setResident(false);
                        return false;
-
                }
-
                return false;
-               
        }
        
-       int makeResident(Object object_, boolean keepResident) {
+       int makeResident(Object object_, boolean keepResident) throws AcornAccessVerificationException, IllegalAcornStateException {
 
                MapValue object = (MapValue)object_;
 
                if(VERIFY) object.verifyAccess();
 
                try {
-
                        object.setForceResident(keepResident);
 
                        if(object.isResident()) {
@@ -480,22 +429,13 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
                        try {
                                refresh(object, false);
                                swap(swapTime, swapSize, object.getKey());
-                       } catch (Throwable t) {
-                               throw new IllegalStateException(t);
                        } finally {
                                releaseMutex();
                        }
-
                        return data.length;
-
                } catch (IOException e) {
-                       
-                       e.printStackTrace();
-                       
+                       throw new IllegalAcornStateException("Unable to makeResident " + identifier, e);
                }
-               
-               return 0;
-               
        }
 
        static int readCounter = 0;
@@ -503,50 +443,48 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
        
        ScheduledThreadPoolExecutor writers;
        
-       void waitPending(MapValue value, boolean hasMutex) {
+       void waitPending(MapValue value, boolean hasMutex) throws IOException, AcornAccessVerificationException, IllegalAcornStateException {
                
-               WriteRunnable r = null;
+               WriteRunnable runnable = null;
                boolean inProgress = false;
                synchronized(pending) {
-                       r = pending.get(value.getKey().toString());
-                       if(r != null) {
-                               synchronized(r) {
-                                       if(r.committed) {
+                       runnable = pending.get(value.getKey().toString());
+                       if(runnable != null) {
+                               synchronized(runnable) {
+                                       if(runnable.committed) {
                                                // just being written - just need to wait
                                                inProgress = true;
                                        } else {
-                                               r.committed = true;
+                                               runnable.committed = true;
                                                // we do the writing
                                        }
                                }
                        }
                }
-               if(r != null) {
+               if(runnable != null) {
                        if(inProgress) {
 //                             System.err.println("reader waits for WriteRunnable to finish");
                                try {
-                                       r.s.acquire();
+                                   if(hasMutex) {
+                                       runnable.borrowMutex = true;
+                                   }
+                                       runnable.s.acquire();
                                } catch (InterruptedException e) {
-                                       e.printStackTrace();
+                                       throw new IllegalAcornStateException(e);
                                }
                        } else {
 //                             System.err.println("reader took WriteRunnable");
-                               try {
-                    r.runReally(hasMutex);
-                } catch (Throwable e) {
-                    e.printStackTrace();
-                    Logger.defaultLogError(e);
-                }
+                runnable.runReally(hasMutex);
                        }
                }
-               
        }
        
        public class WriteRunnable implements Runnable {
 
-               Path bytes;
-               MapValue impl;
-               boolean committed = false;
+               private Path bytes;
+               private MapValue impl;
+               private boolean committed = false;
+               private boolean borrowMutex = false;
                private Semaphore s = new Semaphore(0);
                
                WriteRunnable(Path bytes, MapValue impl) {
@@ -556,48 +494,77 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
                
                @Override
                public void run() {
-                       synchronized(impl) {
-
-                               synchronized(this) {
-                               
-                                       if(committed) return;
-                                       
-                                       committed = true;
-                               
-                               }
-                   try {
-                       runReally(false);
-                   } catch (Throwable e) {
-                       e.printStackTrace();
-                       Logger.defaultLogError(e);
-                   }
-                       }
+                   try {
+                       synchronized(impl) {
+    
+                               synchronized(this) {
+                               
+                                       if(committed)
+                                           return;
+                                       
+                                       committed = true;
+                               }
+                    runReally(false);
+                       }
+                   } catch (Throwable t) {
+                       if (t instanceof IllegalAcornStateException) {
+                           manager.notSafeToMakeSnapshot((IllegalAcornStateException)t);
+                       } else {
+                           manager.notSafeToMakeSnapshot(new IllegalAcornStateException(t));
+                       }
+                       t.printStackTrace();
+                       Logger.defaultLogError(t);
+                   }
                }
 
-               public void runReally(boolean hasMutex) throws IOException {
-               
-                       if(!hasMutex)
-                               impl.acquireMutex();
-                       
-                       try {
-                               
-                               // These have been set in method persist
-                               assert(!impl.isResident());
-                               assert(!impl.isDirty());
-                               
-                               impl.toFile(bytes);
-
-                               synchronized(pending) {
-                                       pending.remove(impl.getKey().toString());
-                                       s.release(Integer.MAX_VALUE);
-                               }
-                       } finally {
-                               if(!hasMutex)
-                                       impl.releaseMutex();
-                       }
-                       
-               }
-       
+        public void runWithMutex() throws IOException, IllegalAcornStateException, AcornAccessVerificationException {
+
+            try {
+                // These have been set in method persist
+                assert (!impl.isResident());
+                assert (!impl.isDirty());
+
+                impl.toFile(bytes);
+            } finally {
+                synchronized (pending) {
+                    pending.remove(impl.getKey().toString());
+                    s.release(Integer.MAX_VALUE);
+                }
+            }
+
+        }
+
+        // Fix WriteRunnable.runReally() to use LRU.MapValue mutex instead of
+        // borrowMutex
+        public void runReally(boolean hasMutex) throws IOException, IllegalAcornStateException, AcornAccessVerificationException {
+
+            if (hasMutex) {
+
+                runWithMutex();
+
+            } else {
+
+                boolean gotMutex = impl.tryAcquireMutex();
+
+                boolean done = false;
+                while (!done) {
+
+                    if (gotMutex || borrowMutex) {
+                        runWithMutex();
+                        done = true;
+                    } else {
+                        System.err.println("Retry mutex acquire");
+                        gotMutex = impl.tryAcquireMutex();
+                    }
+
+                }
+
+                if (gotMutex)
+                    impl.releaseMutex();
+
+            }
+
+        }
        }
        
        public Path getDirectory() {
@@ -609,10 +576,9 @@ public class LRU<MapKey,MapValue extends LRUObject<MapKey, MapValue>> {
         * 
         */
        
-       protected void verifyAccess() {
-//         assert (mutex.availablePermits() == 0);
+       protected void verifyAccess() throws AcornAccessVerificationException {
                if (mutex.availablePermits() != 0)
-                   throw new IllegalStateException("identifier=" + identifier + " mutex has " + mutex.availablePermits() + " available permits, should be 0! Current mutexOwner is " + mutexOwner);
+                   throw new AcornAccessVerificationException("identifier=" + identifier + " mutex has " + mutex.availablePermits() + " available permits, should be 0! Current mutexOwner is " + mutexOwner);
        }
        
        /*
index 1079bf5f0decedacf409d1404d6a5d05b957a333..3194d591e0b37e8712e8cabf3cc1afcb9549a754 100644 (file)
@@ -7,6 +7,8 @@ import java.util.concurrent.TimeUnit;
 
 import org.simantics.acorn.FileIO;
 import org.simantics.acorn.Persistable;
+import org.simantics.acorn.exception.AcornAccessVerificationException;
+import org.simantics.acorn.exception.IllegalAcornStateException;
 import org.simantics.utils.datastructures.Pair;
 
 public abstract class LRUObject<MapKey, MapValue extends LRUObject<MapKey, MapValue>> implements Persistable {
@@ -59,10 +61,8 @@ public abstract class LRUObject<MapKey, MapValue extends LRUObject<MapKey, MapVa
                return key;
        }
        
-       public void acquireMutex() {
-               
+       public void acquireMutex() throws IllegalAcornStateException {
                try {
-
                        while(!mutex.tryAcquire(3, TimeUnit.SECONDS)) {
                                System.err.println("Mutex is taking a long time to acquire - owner is " + mutexOwner);
                        }
@@ -71,7 +71,7 @@ public abstract class LRUObject<MapKey, MapValue extends LRUObject<MapKey, MapVa
                                mutexOwner = Thread.currentThread();
 
                } catch (InterruptedException e) {
-                       throw new IllegalStateException(e);
+                       throw new IllegalAcornStateException(e);
                }
        }
        
@@ -85,21 +85,31 @@ public abstract class LRUObject<MapKey, MapValue extends LRUObject<MapKey, MapVa
 
        @Override
        public void toFile(Path bytes) throws IOException {
-               if(VERIFY) verifyAccess();
-               Pair<byte[],Integer> pair = toBytes();
-               byte[] data = pair.first;
-               int length = pair.second;
-               FileIO fio = FileIO.get(bytes);
-               int offset = fio.saveBytes(data, length, overwrite());
-               setPosition(offset, length);
-       }
-       
-       public int makeResident() {
+               if(VERIFY) {
+                   try {
+                verifyAccess();
+            } catch (AcornAccessVerificationException e) {
+                throw new IOException("Exception occured during toFile for file " + fileName, e);
+            }
+               }
+        try {
+            Pair<byte[], Integer> pair = toBytes();
+            byte[] data = pair.first;
+            int length = pair.second;
+            FileIO fio = FileIO.get(bytes);
+            int offset = fio.saveBytes(data, length, overwrite());
+            setPosition(offset, length);
+        } catch (AcornAccessVerificationException | IllegalAcornStateException e) {
+            throw new IOException("Exception occured during toFile for file " + fileName, e);
+        }
+    }
+       
+       public int makeResident() throws AcornAccessVerificationException, IllegalAcornStateException {
                if(VERIFY) verifyAccess();
                return LRU.makeResident(this, false);
        }
 
-       public int makeResident(boolean keepResident) {
+       public int makeResident(boolean keepResident) throws AcornAccessVerificationException, IllegalAcornStateException {
                if(VERIFY) verifyAccess();
                return LRU.makeResident(this, true);
        }
@@ -111,24 +121,24 @@ public abstract class LRUObject<MapKey, MapValue extends LRUObject<MapKey, MapVa
        abstract void release();
        abstract String getExtension();
        
-       String getStateKey() {
+       String getStateKey() throws IllegalAcornStateException, AcornAccessVerificationException {
                String result = getKey().toString() + "#" + getDirectory().getFileName() + "#" + getOffset() + "#" + getLength(); 
                if(offset == -1)
-                   throw new IllegalStateException(result);
+                   throw new IllegalAcornStateException(result);
                return result; 
        }
 
-       long getLastAccessTime() {
+       long getLastAccessTime() throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
                return accessTime;
        }
        
-       void accessed() {
+       void accessed() throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
                accessTime = AccessTime.getInstance().getAccessTime();
        }
        
-       boolean persist() {
+       boolean persist() throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
                if(LRU.persist(this)) {
                        readDirectory = LRU.getDirectory();
@@ -138,44 +148,44 @@ public abstract class LRUObject<MapKey, MapValue extends LRUObject<MapKey, MapVa
                }
        }
        
-       void setForceResident(boolean value) {
+       void setForceResident(boolean value) throws AcornAccessVerificationException {
         if(VERIFY) verifyAccess();
         forceResident = value;
 //        isForceResidentSetAfterLastGet = true;
        }
        
-       boolean canBePersisted() {
+       boolean canBePersisted() throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
 //             isForceResidentSetAfterLastGet = false;
                return !forceResident;
        }
        
-       boolean isDirty() {
+       boolean isDirty() throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
                return dirty;
        }
        
-       boolean isResident() {
+       boolean isResident() throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
                return resident;
        }
        
-       String getFileName() {
+       String getFileName() throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
                return fileName;
        }
 
-       void setResident(boolean value) {
+       void setResident(boolean value) throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
                resident = value;
        }
        
-       void setDirty(boolean value) {
+       void setDirty(boolean value) throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
                dirty = value;
        }
        
-       byte[] readFile() throws IOException {
+       byte[] readFile() throws IOException, AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
                Path dir = getDirectory();
                Path f = dir.resolve(getFileName());
@@ -189,18 +199,19 @@ public abstract class LRUObject<MapKey, MapValue extends LRUObject<MapKey, MapVa
 
        abstract protected boolean overwrite();
        
-       abstract protected Pair<byte[],Integer> toBytes();
+       abstract protected Pair<byte[],Integer> toBytes() throws IllegalAcornStateException;
        
-       protected void setDirty() {
+       protected void setDirty() throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
                dirty = true;
        }
        
-       protected void verifyAccess() {
-               assert(mutex.availablePermits() == 0);
+       protected void verifyAccess() throws AcornAccessVerificationException {
+        if (mutex.availablePermits() != 0)
+            throw new AcornAccessVerificationException("fileName=" + fileName + " mutex has " + mutex.availablePermits() + " available permits, should be 0! Current mutexOwner is " + mutexOwner);
        }
 
-       protected synchronized void cancelForceResident() {
+       protected synchronized void cancelForceResident() throws AcornAccessVerificationException {
                setForceResident(false);
        }
        
@@ -208,27 +219,27 @@ public abstract class LRUObject<MapKey, MapValue extends LRUObject<MapKey, MapVa
         * Private implementation details
         */
        
-       private int getOffset() {
+       private int getOffset() throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
                return offset;
        }
        
-       private int getLength() {
+       private int getLength() throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
                return length;
        }
        
-       private void setPosition(int offset, int length) {
+       private void setPosition(int offset, int length) throws AcornAccessVerificationException, IllegalAcornStateException {
                if(VERIFY) verifyAccess();
                if(offset == -1)
-                   throw new IllegalStateException();
+                   throw new IllegalAcornStateException("offset == -1 for " + fileName + " in " + readDirectory.toAbsolutePath() + ", dirty=" + dirty + ", resident=" + resident + ", forceResident=" + forceResident);
                this.offset = offset;
                this.length = length;
                if(overwrite() && offset > 0)
-                       throw new IllegalStateException();
+                   throw new IllegalAcornStateException("overwrite() == true &&  offset > 0 for " + fileName + " in " + readDirectory.toAbsolutePath() + ", dirty=" + dirty + ", resident=" + resident + ", forceResident=" + forceResident);
        }
        
-       private Path getDirectory() {
+       private Path getDirectory() throws AcornAccessVerificationException {
                if(VERIFY) verifyAccess();
                return readDirectory;
        }
index 5a96be2df1ef0c3cd4476a890544f6ba3c185ba0..0fb29333b50d527e781cfbe5285c9411ec646ea8 100644 (file)
@@ -11,7 +11,7 @@ import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Arrays;
 
-import org.simantics.acorn.InvalidHeadStateException;
+import org.simantics.acorn.exception.InvalidHeadStateException;
 
 public class HeadState implements Serializable {