X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.acorn%2Fsrc%2Forg%2Fsimantics%2Facorn%2FGraphClientImpl2.java;h=dce477ebeae0fdf35d1db078acfd7e6e885ea825;hp=05f9c8de00b66c315f9a6c5317026f28c0c664cb;hb=c26409b1caf2f1e560d37c5befd11b442399c3fe;hpb=591f4572f18d20a08a797a8e5c4a8dfc1b3320c1 diff --git a/bundles/org.simantics.acorn/src/org/simantics/acorn/GraphClientImpl2.java b/bundles/org.simantics.acorn/src/org/simantics/acorn/GraphClientImpl2.java index 05f9c8de0..dce477ebe 100644 --- a/bundles/org.simantics.acorn/src/org/simantics/acorn/GraphClientImpl2.java +++ b/bundles/org.simantics.acorn/src/org/simantics/acorn/GraphClientImpl2.java @@ -21,19 +21,19 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; +import org.simantics.acorn.MainProgram.MainProgramRunnable; 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; +import org.simantics.acorn.lru.ClusterChangeSet.Entry; import org.simantics.acorn.lru.ClusterInfo; import org.simantics.acorn.lru.ClusterStreamChunk; import org.simantics.acorn.lru.ClusterUpdateOperation; -import org.simantics.acorn.lru.ClusterChangeSet.Entry; import org.simantics.db.ClusterCreator; import org.simantics.db.Database; import org.simantics.db.ServiceLocator; -import org.simantics.db.common.utils.Logger; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.SDBException; import org.simantics.db.server.ProCoreException; @@ -42,11 +42,14 @@ import org.simantics.db.service.ClusterUID; import org.simantics.db.service.LifecycleSupport; import org.simantics.utils.datastructures.Pair; import org.simantics.utils.logging.TimeLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import gnu.trove.map.hash.TLongObjectHashMap; public class GraphClientImpl2 implements Database.Session { - + + private static final Logger LOGGER = LoggerFactory.getLogger(GraphClientImpl2.class); public static final boolean DEBUG = false; public final ClusterManager clusters; @@ -86,6 +89,7 @@ public class GraphClientImpl2 implements Database.Session { load(); ClusterSetsSupport cssi = locator.getService(ClusterSetsSupport.class); cssi.setReadDirectory(clusters.lastSessionDirectory); + cssi.updateWriteDirectory(clusters.workingDirectory); mainProgram = new MainProgram(this, clusters); executor.execute(mainProgram); } @@ -122,10 +126,10 @@ public class GraphClientImpl2 implements Database.Session { mainProgram.mutex.release(); } } catch (IllegalAcornStateException | ProCoreException e) { - Logger.defaultLogError(e); + LOGGER.error("Snapshotting failed", e); unexpectedClose = true; } catch (InterruptedException e) { - Logger.defaultLogError(e); + LOGGER.error("Snapshotting interrupted", e); } finally { try { if(tr != null) @@ -135,11 +139,11 @@ public class GraphClientImpl2 implements Database.Session { try { support.close(); } catch (DatabaseException e1) { - Logger.defaultLogError(e1); + LOGGER.error("Failed to close database as a safety measure due to failed snapshotting", e1); } } } catch (ProCoreException e) { - Logger.defaultLogError(e); + LOGGER.error("Failed to end snapshotting write transaction", e); } } } @@ -182,7 +186,7 @@ public class GraphClientImpl2 implements Database.Session { @Override public void close() throws ProCoreException { - System.err.println("Closing " + this + " and mainProgram " + mainProgram); + LOGGER.info("Closing " + this + " and mainProgram " + mainProgram); if(!closed && !isClosing) { isClosing = true; try { @@ -239,18 +243,17 @@ public class GraphClientImpl2 implements Database.Session { @Override 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); -// } catch (SDBException e) { -// e.printStackTrace(); -// throw new ProCoreException(e); -// } -// clusters.state.headChangeSetId++; -// return clusters.state.headChangeSetId; + // Accept and finalize current transaction and then undo it + acceptCommit(transactionId, changeSetId, metadata); + + try { + undo(new long[] {changeSetId+1}, onChangeSetUpdate); + clusters.state.headChangeSetId++; + return clusters.state.headChangeSetId; + } catch (SDBException e) { + LOGGER.error("Failed to undo cancelled transaction", e); + throw new ProCoreException(e); + } } @Override @@ -604,89 +607,111 @@ public class GraphClientImpl2 implements Database.Session { clusters.clusterLRU.releaseMutex(); } } - + @Override public boolean undo(long[] changeSetIds, OnChangeSetUpdate onChangeSetUpdate) throws SDBException { - try { - final ArrayList> clusterChanges = new ArrayList>(); - - UndoClusterSupport support = new UndoClusterSupport(clusters); - - final int changeSetId = clusters.state.headChangeSetId; - - if(ClusterUpdateProcessorBase.DEBUG) - System.err.println(" === BEGIN UNDO ==="); - - for(int i=0;i ccss = clusters.getChanges(id); - - for(int j=0;j 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); - } + + Exception exception = mainProgram.runIdle(new MainProgramRunnable() { + + @Override + public void run() throws Exception { + + try { + + final ArrayList> clusterChanges = new ArrayList>(); + + UndoClusterSupport support = new UndoClusterSupport(clusters); + + final int changeSetId = clusters.state.headChangeSetId; + + if(ClusterUpdateProcessorBase.DEBUG) + System.err.println(" === BEGIN UNDO ==="); + + for(int i=0;i ccss = clusters.getChanges(id); + + for(int j=0;j 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); + } + + } + + @Override + public void done() { + + } + + }); + + if(exception instanceof SDBException) throw (SDBException)exception; + else if(exception != null) throw new IllegalAcornStateException(exception); + return false; + } public ServiceLocator getServiceLocator() { @@ -702,29 +727,67 @@ public class GraphClientImpl2 implements Database.Session { public boolean rolledback() { return clusters.rolledback(); } + + public void purge() throws IllegalAcornStateException { + clusters.purge(locator); + } - - - - - - - - - - - //////////////////////// - - - - - - - - - - - - + public void purgeDatabase() { + + if (isClosing || unexpectedClose) + return; + + saver.execute(new Runnable() { + + @Override + public void run() { + Transaction tr = null; + try { + // First take a write transaction + tr = askWriteTransaction(-1); + // Then make sure that MainProgram is idling + mainProgram.mutex.acquire(); + try { + synchronized(mainProgram) { + if(mainProgram.operations.isEmpty()) { + purge(); + } else { + // MainProgram is becoming busy again - delay snapshotting + return; + } + } + } finally { + mainProgram.mutex.release(); + } + } catch (IllegalAcornStateException | ProCoreException e) { + LOGGER.error("Purge failed", e); + unexpectedClose = true; + } catch (InterruptedException e) { + LOGGER.error("Purge interrupted", e); + } finally { + try { + if(tr != null) + endTransaction(tr.getTransactionId()); + if (unexpectedClose) { + LifecycleSupport support = getServiceLocator().getService(LifecycleSupport.class); + try { + support.close(); + } catch (DatabaseException e1) { + LOGGER.error("Failed to close database as a safety measure due to failed purge", e1); + } + } + } catch (ProCoreException e) { + LOGGER.error("Failed to end purge write transaction", e); + } + } + } + }); + + } + + public long getTailChangeSetId() { + return clusters.getTailChangeSetId(); + } + }