From: Tuukka Lehtonen Date: Wed, 5 Jul 2017 08:05:47 +0000 (+0300) Subject: Merge "OptionGroup: fixed Names field & ListItem disabled / selected flags" X-Git-Tag: v1.31.0~273 X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=commitdiff_plain;h=edbb4df64407826271ee6423451401684e9cd68c;hp=02fa679efaabc3c88c2abbeed0b89106effdbe18 Merge "OptionGroup: fixed Names field & ListItem disabled / selected flags" --- diff --git a/bundles/org.simantics.acorn/src/org/simantics/acorn/lru/LRU.java b/bundles/org.simantics.acorn/src/org/simantics/acorn/lru/LRU.java index 690ba426f..48b7d4b10 100644 --- a/bundles/org.simantics.acorn/src/org/simantics/acorn/lru/LRU.java +++ b/bundles/org.simantics.acorn/src/org/simantics/acorn/lru/LRU.java @@ -556,18 +556,28 @@ public class LRU> { boolean gotMutex = impl.tryAcquireMutex(); boolean done = false; - // TODO: fix this properly pleease int count = 0; + long startTime = 0; while (!done) { if (gotMutex || borrowMutex) { runWithMutex(); done = true; } else { - if (count % 100 == 0) + if (count % 10 == 0) { + // Taking too long, sleep for a while. LOGGER.warn("Retry mutex acquire"); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + } + } gotMutex = impl.tryAcquireMutex(); - count++; + long currentTime = System.currentTimeMillis(); + if ((currentTime - startTime) > 10) { + startTime = currentTime; + count++; + } } } diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/DelayedWriteGraph.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/DelayedWriteGraph.java index dec1f5396..44e23d017 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/DelayedWriteGraph.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/DelayedWriteGraph.java @@ -12,8 +12,7 @@ package org.simantics.db.impl.graph; -import java.io.DataInput; -import java.io.DataOutput; +import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -22,10 +21,9 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; +import java.nio.file.Files; import java.util.ArrayList; import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.List; import java.util.Set; import java.util.TreeMap; import java.util.UUID; @@ -33,14 +31,10 @@ import java.util.UUID; import org.eclipse.core.runtime.Platform; import org.simantics.databoard.Bindings; import org.simantics.databoard.accessor.Accessor; -import org.simantics.databoard.accessor.reference.ChildReference; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.error.BindingConstructionException; -import org.simantics.databoard.binding.impl.BindingPrintContext; -import org.simantics.databoard.serialization.SerializationException; import org.simantics.databoard.serialization.Serializer; import org.simantics.databoard.type.Datatype; -import org.simantics.databoard.util.IdentityPair; import org.simantics.databoard.util.binary.RandomAccessBinary; import org.simantics.db.Metadata; import org.simantics.db.ReadGraph; @@ -73,7 +67,6 @@ import org.simantics.db.service.XSupport; import org.simantics.layer0.Layer0; import org.simantics.utils.datastructures.MapList; -import gnu.trove.list.array.TIntArrayList; import gnu.trove.map.hash.TIntIntHashMap; import gnu.trove.map.hash.TObjectIntHashMap; @@ -82,164 +75,12 @@ import gnu.trove.map.hash.TObjectIntHashMap; * immediately but with an explicit commit method. All read operations * return results based on the old graph. */ -public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, ByteReader { - - private static final boolean DEBUG = false; - public static int BUFFER = 65536; - - static class Haxx extends Binding { - - static final Serializer serializer = new Serializer() { - - public byte[] serialize(Object obj) throws SerializationException { - return (byte[])obj; - } - - @Override - public void serialize(DataOutput out, - TObjectIntHashMap identities, Object obj) - throws IOException { - throw new Error("Not supported."); - } - - @Override - public void serialize(DataOutput out, Object obj) - throws IOException { - throw new Error("Not supported."); - } - - @Override - public Object deserialize(DataInput in, List identities) - throws IOException { - throw new Error("Not supported."); - } - - @Override - public Object deserialize(DataInput in) throws IOException { - throw new Error("Not supported."); - } - - @Override - public void deserializeTo(DataInput in, List identities, - Object obj) throws IOException { - throw new Error("Not supported."); - } - - @Override - public void deserializeTo(DataInput in, Object obj) - throws IOException { - throw new Error("Not supported."); - } - - @Override - public void skip(DataInput in, List identities) - throws IOException { - throw new Error("Not supported."); - } - - @Override - public void skip(DataInput in) throws IOException { - throw new Error("Not supported."); - } - - @Override - public Integer getConstantSize() { - throw new Error("Not supported."); - } - - @Override - public int getSize(Object obj, TObjectIntHashMap identities) - throws IOException { - throw new Error("Not supported."); - } - - @Override - public int getSize(Object obj) throws IOException { - throw new Error("Not supported."); - } - - @Override - public int getMinSize() { - throw new Error("Not supported."); - } - - }; - - @Override - public Serializer serializer() { - return serializer; - } - - @Override - public void accept(Visitor1 v, Object obj) { - throw new Error("Not supported."); - } - - @Override - public T accept(Visitor v) { - throw new Error("Not supported."); - } - - @Override - public boolean isInstance(Object obj) { - throw new Error("Not supported."); - } - - @Override - public void assertInstaceIsValid(Object obj, Set validInstances) - throws org.simantics.databoard.binding.error.BindingException { - throw new Error("Not supported."); - } - - @Override - public int deepHashValue(Object value, - IdentityHashMap hashedObjects) - throws org.simantics.databoard.binding.error.BindingException { - throw new Error("Not supported."); - } - - @Override - public int deepCompare(Object o1, Object o2, - Set> compareHistory) - throws org.simantics.databoard.binding.error.BindingException { - throw new Error("Not supported."); - } - - @Override - public void readFrom(Binding srcBinding, Object src, Object dst) - throws org.simantics.databoard.binding.error.BindingException { - throw new Error("Not supported."); - } - - @Override - public Object readFromTry(Binding srcBinding, Object src, Object dst) - throws org.simantics.databoard.binding.error.BindingException { - throw new Error("Not supported."); - } - - @Override - protected void toString(Object value, BindingPrintContext ctx) throws org.simantics.databoard.binding.error.BindingException { - throw new Error("Not supported."); - } - - @Override - public int getComponentCount() { - throw new Error("Not supported."); - } +public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, ByteReader, Closeable { - @Override - public Binding getComponentBinding(int index) { - throw new Error("Not supported."); - } + private static final boolean DEBUG = false; + private static final int BUFFER_SIZE = 512*1024; - @Override - public Binding getComponentBinding(ChildReference path) { - throw new Error("Not supported."); - } - - } - - private static final Haxx haxx = new Haxx(); + private static final PassthroughSerializerBinding PASSTHROUGH = new PassthroughSerializerBinding(); private final int TERM = 0; private final int CLAIM = 1; @@ -248,30 +89,11 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte private final int DENY = 5; private final int DENY_VALUE = 6; private final int COMMIT_AND_CONTINUE = 7; - - static class ClusterSet { - public Resource resource; - ClusterSet() { - ids = new TIntArrayList(); - old = false; - } - ClusterSet(boolean old, Resource r) { - ids = new TIntArrayList(); - this.old = old; - this.resource = r; - } - void add(int id) { - ids.add(id); - } - private TIntArrayList ids; - private final boolean old; // true if - boolean isNew() { - return !old; - } - } - public class State { + + private static class State { public File tempFile; public FileOutputStream out; + public FileInputStream in; public ArrayList idToResource = new ArrayList(); public TIntIntHashMap externalToId = new TIntIntHashMap(); public ArrayList idToBinding = new ArrayList(); @@ -285,26 +107,31 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte public int valueCount = 0; public int fileCount = 0; } - - public State writeState; - public TreeMap metadata = new TreeMap(); - - Layer0 b; - Session session; + + private State writeState; + private TreeMap metadata = new TreeMap(); + + private FileChannel channel; + private byte[] bytes = new byte[BUFFER_SIZE]; + private ByteBuffer bb = ByteBuffer.wrap(bytes); + private int byteIndex = 0; + + private Layer0 b; + private Session session; + public static Resource convertDelayedResource(Resource r) { - if (r instanceof InternalResource) { - InternalResource ri = (InternalResource)r; - return ri.resource; - } + if (r instanceof InternalResource) + return ((InternalResource) r).resource; return r; } + private static class InternalResource implements Resource { int id; long clusterId = 0; Resource resource = null; Resource clusterSet = null; - + public InternalResource(int id, long clusterId) { this.id = id; this.clusterId = clusterId; @@ -314,7 +141,7 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte this.id = id; this.clusterSet = clusterSet; } - + @Override public long getResourceId() { throw new UnsupportedOperationException(); @@ -324,7 +151,7 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte public Resource get() { return this; } - + @Override public boolean isPersistent() { return false; @@ -332,11 +159,9 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte @Override public int compareTo(Resource o) { - if(o instanceof InternalResource) { - return Integer.compare(id, ((InternalResource)o).id); - } else { - return -1; - } + if(o instanceof InternalResource) + return Integer.compare(id, ((InternalResource)o).id); + return -1; } @Override @@ -346,7 +171,7 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte result = prime * result + id; return result; } - + @Override public int getThreadHash() { return hashCode(); @@ -365,12 +190,12 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte return false; return true; } - @Override public boolean equalsResource(Resource other) { return equals(other); } + @Override public String toString() { StringBuilder sb = new StringBuilder(32); @@ -432,7 +257,7 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte session = g.getSession(); b = Layer0.getInstance(g); this.writeState = state; - } + } public DelayedWriteGraph newSync() { return new DelayedWriteGraph(this, writeState); @@ -715,7 +540,7 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte if (ws.hasClusterSet(null, clusterSet)) throw new ClusterSetExistException("Cluster set exist already. Resource=" + clusterSet); writeState.clusterSetsForExistingResources.add(clusterSet); - } else { + } else { if(!writeState.clusterSets.add(clusterSet)) throw new ClusterSetExistException("Cluster set exist already. Resource=" + clusterSet); } @@ -787,25 +612,25 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte } } + private OutputStream valueWriter = new OutputStream() { + @Override + public void write(int b) throws IOException { + writeByte(b); + } + }; + @Override public void claimValue(Resource resource, Object value, Binding binding) throws ServiceException { try { - + writeByte(CLAIM_VALUE_B); writeInt(getId(resource)); Serializer serializer = binding.serializer(); int size = serializer.getSize(value); writeInt(size); - serializer.serialize(new OutputStream() { - - @Override - public void write(int b) throws IOException { - writeByte(b); - } - - }, value); - + serializer.serialize(valueWriter, value); + } catch(IOException e) { Logger.defaultLogError(e); throw new ServiceException(e); @@ -832,86 +657,76 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte public void flushCluster(Resource r) throws ServiceException { throw new ServiceException("Operation flushCluster(" + r + " not implemented."); } - - private FileChannel channel; - byte[] bytes = new byte[BUFFER]; - byte[] buffer = new byte[BUFFER]; - ByteBuffer bb = ByteBuffer.wrap(bytes); - int byteIndex = 0; - - private void writeReset(int size) { + private void writeReset(int size) { byteIndex = 0; bb.position(0); bb.limit(size); try { - - if(writeState.tempFile == null) { - + if (writeState.tempFile == null) { File workspace = Platform.getLocation().toFile(); File temp = new File(workspace, "tempFiles"); - temp.mkdirs(); - File base = new File(temp, "delayed"); - base.mkdirs(); + Files.createDirectories(base.toPath()); writeState.tempFile = new File(base, UUID.randomUUID().toString()); writeState.out = new FileOutputStream(writeState.tempFile); channel = writeState.out.getChannel(); - } for (int got=0;got < size;) { int n = channel.write(bb); if (n <= 0) { - new Exception().printStackTrace(); + Logger.defaultLogError(new Exception("FileChannel.write returned " + n)); return; } got += n; } } catch (IOException e) { - e.printStackTrace(); + Logger.defaultLogError("Failed to write buffer of " + size + " bytes to temporary file " + writeState.tempFile, e); } } private void reset() { byteIndex = 0; - try { - bb.clear(); - for(int got=0; got < BUFFER;) { - int n = channel.read(bb); - if (n <= 0) - return; - got += n; + bb.clear(); + if (channel != null) { + try { + for(int got=0; got < BUFFER_SIZE;) { + int n = channel.read(bb); + if (n <= 0) + return; + got += n; + } + } catch (IOException e) { + Logger.defaultLogError("FileChannel.read failed", e); } - } catch (IOException e) { - e.printStackTrace(); } } private void writeInt(int i) { - if(byteIndex < (BUFFER-4)) { + if(byteIndex < (BUFFER_SIZE-4)) { bytes[byteIndex++] = (byte)(i&0xff); bytes[byteIndex++] = (byte)((i>>>8)&0xff); bytes[byteIndex++] = (byte)((i>>>16)&0xff); bytes[byteIndex++] = (byte)((i>>>24)&0xff); - if (byteIndex == BUFFER) - writeReset(BUFFER); + if (byteIndex == BUFFER_SIZE) + writeReset(BUFFER_SIZE); } else { - int has = BUFFER-byteIndex; - if(has == 0) writeReset(BUFFER); + int has = BUFFER_SIZE-byteIndex; + if(has == 0) writeReset(BUFFER_SIZE); bytes[byteIndex++] = (byte)(i&0xff); - if(has == 1) writeReset(BUFFER); + if(has == 1) writeReset(BUFFER_SIZE); bytes[byteIndex++] = (byte)((i>>>8)&0xff); - if(has == 2) writeReset(BUFFER); + if(has == 2) writeReset(BUFFER_SIZE); bytes[byteIndex++] = (byte)((i>>>16)&0xff); - if(has == 3) writeReset(BUFFER); + if(has == 3) writeReset(BUFFER_SIZE); bytes[byteIndex++] = (byte)((i>>>24)&0xff); - if(has == 4) writeReset(BUFFER); + if(has == 4) writeReset(BUFFER_SIZE); } } - + private int readInt() { - if(byteIndex < (BUFFER-4)) { + if(byteIndex < (BUFFER_SIZE-4)) { int result = (int) ((bytes[byteIndex++] & 0xff) | ((bytes[byteIndex++] & 0xff)<<8) | @@ -919,7 +734,7 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte ((bytes[byteIndex++] & 0xff)<<24)); return result; } else { - int has = BUFFER-byteIndex; + int has = BUFFER_SIZE-byteIndex; int result = 0; if(has == 0) reset(); result = (int)(bytes[byteIndex++] & 0xff); @@ -933,44 +748,40 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte return result; } } - + private byte readByte() { byte result = bytes[byteIndex++]; - if(byteIndex == BUFFER) reset(); + if(byteIndex == BUFFER_SIZE) reset(); return result; } private void writeByte(int b) { bytes[byteIndex++] = (byte)b; - if(byteIndex == BUFFER) writeReset(BUFFER); + if(byteIndex == BUFFER_SIZE) writeReset(BUFFER_SIZE); } - + private void writeBytes(byte[] data) { - int has = BUFFER-byteIndex; + int has = BUFFER_SIZE-byteIndex; int amount = data.length; if(has > amount) { System.arraycopy(data, 0, bytes, byteIndex, amount); byteIndex += amount; } else { System.arraycopy(data, 0, bytes, byteIndex, has); - writeReset(BUFFER); + writeReset(BUFFER_SIZE); ByteBuffer bb2 = ByteBuffer.wrap(data); bb2.position(has); try { channel.write(bb2); } catch (IOException e) { - e.printStackTrace(); + Logger.defaultLogError("FileChannel.write failed", e); } } } - - public byte[] readBytes(int amount) { - return readBytes(buffer, amount); - } - + public byte[] readBytes(byte[] result, int amount) { if(result == null) result = new byte[amount]; - int has = BUFFER-byteIndex; + int has = BUFFER_SIZE-byteIndex; if(has > amount) { System.arraycopy(bytes, byteIndex, result, 0, amount); byteIndex += amount; @@ -982,39 +793,46 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte try { got += channel.read(bb2); if(got == -1) { - new Exception().printStackTrace(); + // End-of-stream, why log this? return result; } - } catch (IOException e) { - e.printStackTrace(); + Logger.defaultLogError("FileChannel.read failed", e); } reset(); } return result; } - + public void commit(final WriteOnlyGraph w, final WriteTraits traits) throws ServiceException { writeState.bindingToId = null; writeState.externalToId = null; - try { - - writeByte(TERM); - if(byteIndex > 0) { + writeByte(TERM); + + if (writeState.out != null) { + // Flush current buffer to file only if backing file has already + // been taken into use. + if (byteIndex > 0) writeReset(byteIndex); + + try (OutputStream out = writeState.out) { + channel.force(false); + } catch (IOException e) { + throw new ServiceException(e); + } finally { + writeState.out = null; } - channel.force(false); - writeState.out.close(); - FileInputStream fs = new FileInputStream(writeState.tempFile); - channel = fs.getChannel(); - - } catch (IOException e) { - throw new ServiceException(e); + try { + writeState.in = new FileInputStream(writeState.tempFile); + channel = writeState.in.getChannel(); + } catch (IOException e) { + throw new ServiceException(e); + } } - + w.getMetadata().putAll(metadata); - + TransferableGraphSupport tgs = w.getService(TransferableGraphSupport.class); // First create all resources defined by clusterId @@ -1094,13 +912,20 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte } reset(); - bb.limit(BUFFER); + bb.limit(BUFFER_SIZE); try { while(true) { byte method = readByte(); - switch(method) { + switch(method) { case TERM: { + if (DEBUG) { + System.out.println("Resources: " + writeState.idToResource.size()); + System.out.println("Statements: " + writeState.statementCount); + System.out.println("Values: " + writeState.valueCount); + System.out.println("Files: " + writeState.fileCount); + System.out.println("Clusters: " + writeState.clusterCount); + } return; } case CLAIM: { @@ -1153,8 +978,6 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte Resource resource = getResource(readInt()); int len = readInt(); tgs.setValue(w, resource, null, this, len); -// byte[] bytes = readBytes(len); -// tgs.setValue(resource, null, bytes); } break; case COMMIT_AND_CONTINUE: { XSupport xs = w.getService(XSupport.class); @@ -1168,18 +991,19 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte else throw new ServiceException(e); } finally { - try { - channel.close(); - channel = null; - } catch (IOException e) { - throw new ServiceException(e); + channel = null; + if (writeState.in != null) { + try (InputStream in = writeState.in) { + } catch (IOException e) { + throw new ServiceException(e); + } finally { + writeState.in = null; + writeState.tempFile.delete(); + } } } -// System.out.println("Resources: " + state.resourceCount); -// System.out.println("Statements: " + state.statementCount); -// System.out.println("Values: " + state.valueCount); } - + private Resource getType(Object value) { Class clazz = value.getClass(); Resource dataType = @@ -1196,12 +1020,12 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte : clazz == String[].class ? b.StringArray : clazz == boolean[].class ? b.BooleanArray : clazz == byte[].class ? b.ByteArray - : clazz == long[].class ? b.LongArray + : clazz == long[].class ? b.LongArray : null ; return dataType; } - + public long newCluster() { return -1 - (++writeState.clusterCount); } @@ -1209,14 +1033,14 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte public long getDefaultCluster() { return writeState.defaultCluster; } - + public void setDefaultCluster(long cluster) { writeState.defaultCluster = cluster; } - + @Override public void syncRequest(final DelayedWrite request) throws DatabaseException { - + try { final DelayedWriteGraph dwg = new DelayedWriteGraph(this); @@ -1232,24 +1056,23 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte }); } catch (DatabaseException e) { - + throw e; - + } catch (Throwable e) { - + throw new DatabaseException(e); - + } finally { - } - + } - + @Override public void syncRequest(WriteOnly request) throws DatabaseException { - + Resource defaultClusterSet = setClusterSet4NewResource(null); - + try { WriteSupport ws = session.getService(WriteSupport.class); ws.performWriteRequest(this, request); @@ -1260,46 +1083,46 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte } finally { setClusterSet4NewResource(defaultClusterSet); } - + } @SuppressWarnings("unchecked") @Override public T getService(Class api) { - + if(ClusteringSupport.class == api) { final ClusteringSupport support = (ClusteringSupport)super.getService(api); return (T)new ClusteringSupport() { - + @Override public Resource getResourceByIndexAndCluster(int resourceIndex, long clusterId) throws DatabaseException, ResourceNotFoundException { return support.getResourceByIndexAndCluster(resourceIndex, clusterId); } - + @Override public Resource getResourceByKey(int resourceKey) throws ResourceNotFoundException { return support.getResourceByKey(resourceKey); } - + @Override public int getNumberOfResources(long clusterId) throws DatabaseException { return support.getNumberOfResources(clusterId); } - + @Override public long getCluster(Resource r) { return support.getCluster(r); } - + @Override public long createCluster() { return newCluster(); } - + @Override public boolean isClusterSet(Resource r) throws DatabaseException { return support.isClusterSet(r); @@ -1309,18 +1132,18 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte public Resource getClusterSetOfCluster(Resource r) throws DatabaseException { return support.getClusterSetOfCluster(r); } - + @Override public Resource getClusterSetOfCluster(long cluster) throws DatabaseException { return support.getClusterSetOfCluster(cluster); } }; - + } else if (TransferableGraphSupport.class == api) { - + final TransferableGraphSupport parentSupport = session.getService(TransferableGraphSupport.class); - + return (T)new TransferableGraphSupport() { @Override @@ -1329,9 +1152,9 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte writeInt(getId(resource)); writeInt(raw.length); writeBytes(raw); - writeInt(getBindingId(haxx)); + writeInt(getBindingId(PASSTHROUGH)); } - + @Override public void setValue(WriteOnlyGraph graph, Resource resource, VirtualGraph provider, ByteReader reader, int amount) throws DatabaseException { @@ -1339,25 +1162,25 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte writeInt(getId(resource)); writeInt(amount); writeBytes(reader.readBytes(null, amount)); - writeInt(getBindingId(haxx)); + writeInt(getBindingId(PASSTHROUGH)); } - + @Override public byte[] getValue(ReadGraph graph, Resource resource) { return parentSupport.getValue(graph, resource); } - + @Override public InputStream getValueStream(ReadGraph graph, Resource resource) { return parentSupport.getValueStream(graph, resource); } - + }; } - + return super.getService(api); - + } @Override @@ -1423,4 +1246,27 @@ public class DelayedWriteGraph extends ReadGraphImpl implements WriteGraph, Byte } } + public void close() { + if (writeState.out != null) { + try (OutputStream out = writeState.out) { + } catch (IOException e) { + Logger.defaultLogError("Failed to close delayed write graph temporary commit output stream", e); + } finally { + writeState.out = null; + } + } + if (writeState.in != null) { + try (InputStream in = writeState.in) { + } catch (IOException e) { + Logger.defaultLogError("Failed to close delayed write graph temporary commit input stream", e); + } finally { + writeState.in = null; + } + } + if (writeState.tempFile != null) { + writeState.tempFile.delete(); + writeState.tempFile = null; + } + } + } diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/PassthroughSerializerBinding.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/PassthroughSerializerBinding.java new file mode 100644 index 000000000..8c95a5151 --- /dev/null +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/PassthroughSerializerBinding.java @@ -0,0 +1,174 @@ +package org.simantics.db.impl.graph; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Set; + +import org.simantics.databoard.accessor.reference.ChildReference; +import org.simantics.databoard.binding.Binding; +import org.simantics.databoard.binding.impl.BindingPrintContext; +import org.simantics.databoard.serialization.SerializationException; +import org.simantics.databoard.serialization.Serializer; +import org.simantics.databoard.util.IdentityPair; + +import gnu.trove.map.hash.TObjectIntHashMap; + +/** + * Originally within DelayedWriteGraph, put in separate file in 1.30.0. + * + * @author Antti Villberg + */ +class PassthroughSerializerBinding extends Binding { + + static final Serializer serializer = new Serializer() { + + public byte[] serialize(Object obj) throws SerializationException { + return (byte[])obj; + } + + @Override + public void serialize(DataOutput out, + TObjectIntHashMap identities, Object obj) + throws IOException { + throw new Error("Not supported."); + } + + @Override + public void serialize(DataOutput out, Object obj) + throws IOException { + throw new Error("Not supported."); + } + + @Override + public Object deserialize(DataInput in, List identities) + throws IOException { + throw new Error("Not supported."); + } + + @Override + public Object deserialize(DataInput in) throws IOException { + throw new Error("Not supported."); + } + + @Override + public void deserializeTo(DataInput in, List identities, + Object obj) throws IOException { + throw new Error("Not supported."); + } + + @Override + public void deserializeTo(DataInput in, Object obj) + throws IOException { + throw new Error("Not supported."); + } + + @Override + public void skip(DataInput in, List identities) + throws IOException { + throw new Error("Not supported."); + } + + @Override + public void skip(DataInput in) throws IOException { + throw new Error("Not supported."); + } + + @Override + public Integer getConstantSize() { + throw new Error("Not supported."); + } + + @Override + public int getSize(Object obj, TObjectIntHashMap identities) + throws IOException { + throw new Error("Not supported."); + } + + @Override + public int getSize(Object obj) throws IOException { + throw new Error("Not supported."); + } + + @Override + public int getMinSize() { + throw new Error("Not supported."); + } + + }; + + @Override + public Serializer serializer() { + return serializer; + } + + @Override + public void accept(Visitor1 v, Object obj) { + throw new Error("Not supported."); + } + + @Override + public T accept(Visitor v) { + throw new Error("Not supported."); + } + + @Override + public boolean isInstance(Object obj) { + throw new Error("Not supported."); + } + + @Override + public void assertInstaceIsValid(Object obj, Set validInstances) + throws org.simantics.databoard.binding.error.BindingException { + throw new Error("Not supported."); + } + + @Override + public int deepHashValue(Object value, + IdentityHashMap hashedObjects) + throws org.simantics.databoard.binding.error.BindingException { + throw new Error("Not supported."); + } + + @Override + public int deepCompare(Object o1, Object o2, + Set> compareHistory) + throws org.simantics.databoard.binding.error.BindingException { + throw new Error("Not supported."); + } + + @Override + public void readFrom(Binding srcBinding, Object src, Object dst) + throws org.simantics.databoard.binding.error.BindingException { + throw new Error("Not supported."); + } + + @Override + public Object readFromTry(Binding srcBinding, Object src, Object dst) + throws org.simantics.databoard.binding.error.BindingException { + throw new Error("Not supported."); + } + + @Override + protected void toString(Object value, BindingPrintContext ctx) throws org.simantics.databoard.binding.error.BindingException { + throw new Error("Not supported."); + } + + @Override + public int getComponentCount() { + throw new Error("Not supported."); + } + + @Override + public Binding getComponentBinding(int index) { + throw new Error("Not supported."); + } + + @Override + public Binding getComponentBinding(ChildReference path) { + throw new Error("Not supported."); + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/adapter/impl/TGRemover.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/adapter/impl/TGRemover.java index aae4b581b..885948834 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/adapter/impl/TGRemover.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/adapter/impl/TGRemover.java @@ -43,10 +43,9 @@ public class TGRemover extends AbstractRemover { TransferableGraphConfiguration2 conf = new TransferableGraphConfiguration2(graph, resource); conf.values = false; - ModelTransferableGraphSource source = graph.syncRequest(new ModelTransferableGraphSourceRequest(conf)); final SerialisationSupport ss = graph.getService(SerialisationSupport.class); - try { + try (ModelTransferableGraphSource source = graph.syncRequest(new ModelTransferableGraphSourceRequest(conf))) { source.forResourceStatements(graph, new TransferableGraphSourceProcedure() { @Override @@ -75,8 +74,6 @@ public class TGRemover extends AbstractRemover { }); - source.closeStreams(); - } catch (Exception e) { throw new DatabaseException(e); } diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/Layer0Utils.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/Layer0Utils.java index beec63aa1..c04ca3cd1 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/Layer0Utils.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/Layer0Utils.java @@ -1394,10 +1394,40 @@ public class Layer0Utils { * @param graph * @param component * for which the identifier is added + * @param add + * true to invoke addLiteral, false to + * invoke claimLiteral * @throws DatabaseException */ - public static void addL0Identifier(WriteGraph graph, Resource component) throws DatabaseException { + public static void claimNewIdentifier(WriteGraph graph, Resource component, boolean add) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); - graph.addLiteral(component, L0.identifier, L0.identifier_Inverse, L0.GUID, GUID.random(), GUID.BINDING); + GUID guid = GUID.random(); + if (add) + graph.addLiteral(component, L0.identifier, L0.identifier_Inverse, L0.GUID, guid, GUID.BINDING); + else + graph.claimLiteral(component, L0.identifier, L0.identifier_Inverse, L0.GUID, guid, GUID.BINDING); + } + + /** + * Sets a new random unique identifier for the specified entity if it already + * has an identifier. If the entity does not have a previous identifier, nothing + * is done. + * + * @param graph + * @param entity + * for which the identifier is added + * @return true if the identifier was renewed, false + * otherwise + * @throws DatabaseException + * @see {@link #claimNewIdentifier(WriteGraph, Resource, boolean)} + */ + public static boolean renewIdentifier(WriteGraph graph, Resource entity) throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + Statement stm = graph.getPossibleStatement(entity, L0.identifier); + if (stm != null) { + graph.claimValue(stm.getObject(), GUID.random(), GUID.BINDING); + return true; + } + return false; } } diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/TGRepresentation.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/TGRepresentation.java index 0f9ffa0a7..ed7ae5193 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/TGRepresentation.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/TGRepresentation.java @@ -1,5 +1,6 @@ package org.simantics.db.layer0.util; +import java.io.IOException; import java.util.Arrays; import java.util.Map; @@ -49,9 +50,11 @@ public class TGRepresentation implements Representation { configuration.exclusionFunction = TGRepresentationUtils.computeExclusionFunction(graph, resources, hints); } - ModelTransferableGraphSource source = graph.syncRequest(new ModelTransferableGraphSourceRequest(configuration)); - return TransferableGraphs.create(graph, source); - + try (ModelTransferableGraphSource source = graph.syncRequest(new ModelTransferableGraphSourceRequest(configuration))) { + return TransferableGraphs.create(graph, source); + } catch (IOException e) { + throw new DatabaseException(e); + } } @SuppressWarnings("unchecked") diff --git a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/SessionImplSocket.java b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/SessionImplSocket.java index 80dc3b9bb..c286f02c7 100644 --- a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/SessionImplSocket.java +++ b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/SessionImplSocket.java @@ -665,6 +665,7 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule } catch (Throwable e) { delayedWriteState.except(e); total.finish(); + dwg.close(); return; } finally { // newGraph.state.barrier.dec(); diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/RouteGraphUtils.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/RouteGraphUtils.java index 1b7376f96..054db497d 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/RouteGraphUtils.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/RouteGraphUtils.java @@ -524,7 +524,7 @@ public class RouteGraphUtils { } } - private static final ConnectionStyle DEFAULT_CONNECTION_STYLE = new ExampleConnectionStyle(); + private static final ConnectionStyle DEFAULT_CONNECTION_STYLE = new BasicConnectionStyle(Color.BLACK, Color.BLACK, 3, ExampleConnectionStyle.SOLID, ExampleConnectionStyle.SOLID, 8); /** * @param graph diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/Paster.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/Paster.java index 667259907..75b0473a1 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/Paster.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/Paster.java @@ -28,6 +28,7 @@ import org.simantics.db.common.utils.CommonDBUtils; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.common.utils.OrderedSetUtils; import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.util.Layer0Utils; import org.simantics.db.layer0.util.RemoverUtil; import org.simantics.db.request.Write; import org.simantics.diagram.content.ConnectionUtil; @@ -863,6 +864,11 @@ public class Paster { graph.claim(copy, L0.ConsistsOf, L0.PartOf, relationCopy); graph.claim(copy, MOD.HasReferenceRelation, MOD.HasReferenceRelation_Inverse, relationCopy); + // #7348: renew reference relation GUID identifiers properly + Layer0Utils.renewIdentifier(graph, relationCopy); + for (Resource invRel : graph.getObjects(relationCopy, L0.ConsistsOf)) + Layer0Utils.renewIdentifier(graph, invRel); + return copy; } diff --git a/bundles/org.simantics.layer0.utils/src/org/simantics/layer0/utils/writer/DelayedGraphWriter.java b/bundles/org.simantics.layer0.utils/src/org/simantics/layer0/utils/writer/DelayedGraphWriter.java index 576bc0b4b..66ffa77de 100644 --- a/bundles/org.simantics.layer0.utils/src/org/simantics/layer0/utils/writer/DelayedGraphWriter.java +++ b/bundles/org.simantics.layer0.utils/src/org/simantics/layer0/utils/writer/DelayedGraphWriter.java @@ -12,9 +12,6 @@ package org.simantics.layer0.utils.writer; -import gnu.trove.map.hash.TIntIntHashMap; -import gnu.trove.map.hash.TIntLongHashMap; - import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; @@ -31,6 +28,9 @@ import org.simantics.db.Resource; import org.simantics.db.WriteOnlyGraph; import org.simantics.db.exception.DatabaseException; +import gnu.trove.map.hash.TIntIntHashMap; +import gnu.trove.map.hash.TIntLongHashMap; + public class DelayedGraphWriter extends AbstractDelayedGraphWriter { protected File file; @@ -45,7 +45,6 @@ public class DelayedGraphWriter extends AbstractDelayedGraphWriter { System.out.println("Temp file: " + file.getAbsolutePath()); s = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file), 1024*1024)); // s = new ObjectOutputStream(backup); - file.deleteOnExit(); } catch (IOException e) { throw new RuntimeException("Opening output stream to temporary file failed", e); @@ -79,13 +78,13 @@ public class DelayedGraphWriter extends AbstractDelayedGraphWriter { assert(value != null); assert(dataType != null); try { - ++internalCount; + ++internalCount; timestamps.add(0); - s.writeByte(1); - writeRef(internalCount); + s.writeByte(1); + writeRef(internalCount); s.writeUnshared(value); - writeRef(getId(dataType)); + writeRef(getId(dataType)); s.writeByte(0); writeRef(current); @@ -110,14 +109,14 @@ public class DelayedGraphWriter extends AbstractDelayedGraphWriter { assert(value != null); assert(dataType != null); try { - ++internalCount; + ++internalCount; timestamps.add(0); - s.writeByte(1); - writeRef(internalCount); + s.writeByte(1); + writeRef(internalCount); s.writeUnshared(value); - writeRef(getId(dataType)); - + writeRef(getId(dataType)); + current = internalCount; } catch (IOException e) { throw new RuntimeException("Writing statement failed.", e); @@ -133,7 +132,7 @@ public class DelayedGraphWriter extends AbstractDelayedGraphWriter { clusterHints.put(current, clusterHint); return this; } - + @Override public GraphWriter createInverse(int cluster, Resource r) { assert(r != null); @@ -147,7 +146,7 @@ public class DelayedGraphWriter extends AbstractDelayedGraphWriter { } return this; } - + @Override public GraphWriter createInverse(Resource r) { assert(r != null); @@ -160,7 +159,7 @@ public class DelayedGraphWriter extends AbstractDelayedGraphWriter { throw new RuntimeException("Writing statement failed.", e); } return this; - } + } protected Resource getResource(WriteOnlyGraph wg, Resource[] internals, long[] resourceIds, int id) { if(id > 0) { @@ -185,124 +184,122 @@ public class DelayedGraphWriter extends AbstractDelayedGraphWriter { @Override public void commit(IProgressMonitor monitor, WriteOnlyGraph wg) throws DatabaseException { - try { - if (s != null) { - s.close(); - s = null; - } + if (s != null) { + s.close(); + s = null; + } externalsInv = null; - - monitor.beginTask("", 100); - - int lastPercentageDone = 0; - long fileLength = file.length(); - -// System.out.println("size of commit file: " + fileLength); - - Resource[] internals = new Resource[internalCount]; - resourceIds = new long[internalCount]; - - + monitor.beginTask("Writing database", 100); FileInputStream fis = new FileInputStream(file); FileChannel fc = fis.getChannel(); - ObjectInputStream is = new ObjectInputStream(new BufferedInputStream(fis, 1024*1024)); - int resourceCounter = 0; - int statementCounter = 0; - int valueCounter = 0; - time = 0; - loop: while(true) { - switch(is.read()) { - case -1: - break loop; - case 0: { - int s = is.readInt(); - int p = is.readInt(); - int o = is.readInt(); - Resource rs = getResource(wg, internals, resourceIds, s); - Resource rp = getResource(wg, internals, resourceIds, p); - Resource ro = getResource(wg, internals, resourceIds, o); - Resource rpInv = inverses.get(p); - wg.claim(rs, rp, rpInv, ro); - statementCounter += 2; - } break; - case 1: { - int id = is.readInt(); - Object value = is.readUnshared(); - int type = is.readInt(); - - Resource r = newResource(wg, internals, id); - wg.claim(r, l0.InstanceOf, null, getResource(wg, internals, resourceIds, type)); - wg.claimValue(r, value); - statementCounter ++; - resourceCounter ++; - valueCounter ++; - - } break; - case 2: { - wg.flushCluster(); - } break; - case 3: { - - int s = is.readInt(); - int t = is.readInt(); - - Resource type = getResource(wg, internals, resourceIds, t); - wg.claim(newResource(wg, internals, s), l0.InstanceOf, null, type); - statementCounter ++; - resourceCounter ++; - - } break; - case 4: { - - int s = is.readInt(); - newResource(wg, internals, s); - resourceCounter ++; - - } break; - case 5: { // InverseOf - - int r1 = is.readInt(); - int r2 = is.readInt(); - - Resource rr1 = getResource(wg, internals, resourceIds, r1); - Resource rr2 = getResource(wg, internals, resourceIds, r2); - wg.claim(rr1, l0.InverseOf, l0.InverseOf, rr2); - statementCounter += 2; - - inverses.put(r1, rr2); - inverses.put(r2, rr1); - - } break; - } - -// if((counter % 200000) == 0) { -// System.out.println("Written " + counter + " statements."); -// } - - double percentageDone = 100.0 * (double) fc.position() / (double) fileLength; - int newPercentageDone = (int) Math.round(percentageDone); - if(newPercentageDone > lastPercentageDone) { - monitor.setTaskName("Writing database (" + newPercentageDone + "%)"); - monitor.worked(newPercentageDone - lastPercentageDone); - lastPercentageDone = newPercentageDone; - } + try (ObjectInputStream is = new ObjectInputStream(new BufferedInputStream(fis, 1024*1024))) { + commit(monitor, wg, is, fc); } - - System.out.println("clusterIds.size() = " + clusterIds.size()); - - System.out.println("Wrote " + resourceCounter + " resources, " + statementCounter + " statements and " + valueCounter + " values."); - } catch (IOException e) { - throw new RuntimeException("Commiting delayed graph writings failed.", e); + throw new DatabaseException("Commiting delayed graph writings failed.", e); } catch (ClassNotFoundException e) { - throw new RuntimeException("Commiting delayed graph writings failed.", e); - } finally { + throw new DatabaseException("Commiting delayed graph writings failed.", e); + } finally { file.delete(); monitor.done(); } } - + + private void commit(IProgressMonitor monitor, WriteOnlyGraph wg, ObjectInputStream is, FileChannel fc) throws DatabaseException, IOException, ClassNotFoundException { + int lastPercentageDone = 0; + long fileLength = file.length(); + //System.out.println("size of commit file: " + fileLength); + + Resource[] internals = new Resource[internalCount]; + resourceIds = new long[internalCount]; + + int resourceCounter = 0; + int statementCounter = 0; + int valueCounter = 0; + time = 0; + while(true) { + switch(is.read()) { + case -1: + System.out.println("clusterIds.size() = " + clusterIds.size()); + System.out.println("Wrote " + resourceCounter + " resources, " + statementCounter + " statements and " + valueCounter + " values."); + return; + + case 0: { + int s = is.readInt(); + int p = is.readInt(); + int o = is.readInt(); + Resource rs = getResource(wg, internals, resourceIds, s); + Resource rp = getResource(wg, internals, resourceIds, p); + Resource ro = getResource(wg, internals, resourceIds, o); + Resource rpInv = inverses.get(p); + wg.claim(rs, rp, rpInv, ro); + statementCounter += 2; + } break; + case 1: { + int id = is.readInt(); + Object value = is.readUnshared(); + int type = is.readInt(); + + Resource r = newResource(wg, internals, id); + wg.claim(r, l0.InstanceOf, null, getResource(wg, internals, resourceIds, type)); + wg.claimValue(r, value); + statementCounter ++; + resourceCounter ++; + valueCounter ++; + + } break; + case 2: { + wg.flushCluster(); + } break; + case 3: { + + int s = is.readInt(); + int t = is.readInt(); + + Resource type = getResource(wg, internals, resourceIds, t); + wg.claim(newResource(wg, internals, s), l0.InstanceOf, null, type); + statementCounter ++; + resourceCounter ++; + + } break; + case 4: { + + int s = is.readInt(); + newResource(wg, internals, s); + resourceCounter ++; + + } break; + case 5: { // InverseOf + + int r1 = is.readInt(); + int r2 = is.readInt(); + + Resource rr1 = getResource(wg, internals, resourceIds, r1); + Resource rr2 = getResource(wg, internals, resourceIds, r2); + wg.claim(rr1, l0.InverseOf, l0.InverseOf, rr2); + statementCounter += 2; + + inverses.put(r1, rr2); + inverses.put(r2, rr1); + + } break; + } + +// if((counter % 200000) == 0) { +// System.out.println("Written " + counter + " statements."); +// } + + double percentageDone = 100.0 * (double) fc.position() / (double) fileLength; + int newPercentageDone = (int) Math.round(percentageDone); + if(newPercentageDone > lastPercentageDone) { + monitor.setTaskName("Writing database (" + newPercentageDone + "%)"); + monitor.worked(newPercentageDone - lastPercentageDone); + lastPercentageDone = newPercentageDone; + } + } + } + private Resource newResource(WriteOnlyGraph wg, Resource[] internals, int s) throws DatabaseException { int clusterHint = clusterHints.get(s); @@ -323,42 +320,6 @@ public class DelayedGraphWriter extends AbstractDelayedGraphWriter { resourceIds[s-1] = r.getResourceId(); return r; } - -// public ValueDescriptor createDescriptor(Object obj) { -// -// if(obj instanceof String[]) -// return new ValueDescriptor(ValueTrait.StaticValue, (String[])obj); -// else if(obj instanceof int[]) -// return new ValueDescriptor(ValueTrait.StaticValue, (int[])obj); -// else if(obj instanceof double[]) -// return new ValueDescriptor(ValueTrait.StaticValue, (double[])obj); -// else if(obj instanceof float[]) -// return new ValueDescriptor(ValueTrait.StaticValue, (float[])obj); -// else if(obj instanceof boolean[]) -// return new ValueDescriptor(ValueTrait.StaticValue, (boolean[])obj); -// else if(obj instanceof long[]) -// return new ValueDescriptor(ValueTrait.StaticValue, (long[])obj); -// else if(obj instanceof byte[]) -// return new ValueDescriptor(ValueTrait.StaticValue, (byte[])obj); -// -// else if(obj instanceof String) -// return new ValueDescriptor(ValueTrait.StaticValue, new String[] {(String)obj}); -// else if(obj instanceof Double) -// return new ValueDescriptor(ValueTrait.StaticValue, new double[] {(Double)obj}); -// else if(obj instanceof Float) -// return new ValueDescriptor(ValueTrait.StaticValue, new float[] {(Float)obj}); -// else if(obj instanceof Integer) -// return new ValueDescriptor(ValueTrait.StaticValue, new int[] {(Integer)obj}); -// else if(obj instanceof Boolean) -// return new ValueDescriptor(ValueTrait.StaticValue, new boolean[] {(Boolean)obj}); -// else if(obj instanceof Byte) -// return new ValueDescriptor(ValueTrait.StaticValue, new byte[] {(Byte)obj}); -// else if(obj instanceof Long) -// return new ValueDescriptor(ValueTrait.StaticValue, new long[] {(Long)obj}); -// -// throw new Error("Wrong type!"); -// -// } @Override public GraphWriter create() { @@ -407,8 +368,7 @@ public class DelayedGraphWriter extends AbstractDelayedGraphWriter { @Override public GraphWriter create(int clusterHint, Resource type) { - - create(type); + create(type); clusterHints.put(current, clusterHint); return this; @@ -432,7 +392,7 @@ public class DelayedGraphWriter extends AbstractDelayedGraphWriter { return this; } - public GraphWriter flush() { + public GraphWriter flush() { try { s.writeByte(2); } catch(IOException e) { diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/ModelingUtils.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/ModelingUtils.java index 753a90292..3054fcaa5 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/ModelingUtils.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/ModelingUtils.java @@ -400,9 +400,7 @@ public class ModelingUtils { Resource project = SimanticsUI.getProject().get(); - try { - - StreamingTransferableGraphFileReader importer = new StreamingTransferableGraphFileReader(new File(fileName)); + try (StreamingTransferableGraphFileReader importer = new StreamingTransferableGraphFileReader(new File(fileName))) { TransferableGraphSource tg = importer.readTG(); final DefaultPasteImportAdvisor advisor = new DefaultPasteImportAdvisor(project) { @@ -2260,7 +2258,7 @@ public class ModelingUtils { Layer0 L0 = Layer0.getInstance(graph); while(!todo.isEmpty()) { Resource resource = todo.remove(todo.size()-1); - Layer0Utils.addL0Identifier(graph, resource); + Layer0Utils.claimNewIdentifier(graph, resource, false); if(deep) todo.addAll(graph.getObjects(resource, L0.ConsistsOf)); } @@ -2291,7 +2289,7 @@ public class ModelingUtils { GUID existing = graph.getPossibleRelatedValue(r, L0.identifier, GUID.BINDING); if(existing == null) { - Layer0Utils.addL0Identifier(graph, r); + Layer0Utils.claimNewIdentifier(graph, r, true); madeChanges = true; } diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/SCLScenegraph.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/SCLScenegraph.java index 5dde0b081..6345a1329 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/SCLScenegraph.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/SCLScenegraph.java @@ -9,11 +9,16 @@ import java.awt.geom.Rectangle2D; import java.io.ByteArrayOutputStream; import java.io.OutputStreamWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Random; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; @@ -24,11 +29,17 @@ import javax.xml.transform.stream.StreamResult; import org.apache.batik.dom.GenericDOMImplementation; import org.apache.batik.svggen.SVGGeneratorContext; import org.apache.batik.svggen.SVGGraphics2D; +import org.simantics.Simantics; +import org.simantics.datatypes.literal.GUID; +import org.simantics.db.ReadGraph; import org.simantics.db.Resource; +import org.simantics.db.common.request.UnaryRead; import org.simantics.db.exception.DatabaseException; +import org.simantics.db.exception.RuntimeDatabaseException; import org.simantics.diagram.elements.DiagramNodeUtil; import org.simantics.diagram.elements.TextGridNode; import org.simantics.diagram.elements.TextNode; +import org.simantics.diagram.stubs.DiagramResource; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.diagram.DiagramHints; import org.simantics.g2d.diagram.IDiagram; @@ -37,6 +48,7 @@ import org.simantics.g2d.diagram.participant.Selection; import org.simantics.g2d.element.IElement; import org.simantics.g2d.scenegraph.ICanvasSceneGraphProvider; import org.simantics.g2d.utils.CanvasUtils; +import org.simantics.layer0.Layer0; import org.simantics.scenegraph.INode; import org.simantics.scenegraph.ParentNode; import org.simantics.scenegraph.g2d.G2DParentNode; @@ -57,6 +69,7 @@ import org.simantics.scenegraph.g2d.nodes.SingleElementNode; import org.simantics.scenegraph.g2d.nodes.connection.RouteGraphNode; import org.simantics.scenegraph.g2d.nodes.spatial.RTreeNode; import org.simantics.scenegraph.utils.NodeUtil; +import org.simantics.scl.runtime.function.Function1; import org.simantics.trend.impl.ItemNode; import org.simantics.utils.threads.ThreadUtils; import org.slf4j.Logger; @@ -435,7 +448,95 @@ public class SCLScenegraph { } - public static String renderSVG(ICanvasContext ctx) { + public static String renderSVG3(ICanvasContext ctx) { + return renderSVG0(ctx, p0 -> p0.stream().collect(Collectors.toMap(p1 -> p1, p2 -> p2))); + } + + /** + * @param graph + * @param component + * @throws DatabaseException + */ + private static Object[] createURIBasedL0Identifier(ReadGraph graph, Resource component) throws DatabaseException { + String uri = graph.getPossibleURI(component); + int hashCode = uri.hashCode(); + Random random = new Random(hashCode); + long l1 = random.nextLong(); + long l2 = random.nextLong(); + return new Object[] { l1, l2 }; + } + + /** + * Default no-op mapper + */ + private static final Function1, Map> mapper = p0 -> p0.stream().collect(Collectors.toMap(p1 -> p1, p2 -> p2)); + + public static String renderSVG(ICanvasContext ctx) { + return renderSVG0(ctx, mapper); + } + + /** + * Renders ICanvasContext into SVG by mapping the SVG id's into URI based + * GUID's + * + * @param ctx + * @return + */ + public static String renderSVGMapIdentifiers(ICanvasContext ctx) { + return renderSVG0(ctx, new Function1, Map>() { + + @Override + public Map apply(Set p0) { + try { + return Simantics.getSession().syncRequest(new UnaryRead, Map>(p0) { + + @Override + public Map perform(ReadGraph graph) throws DatabaseException { + ModelingResources MOD = ModelingResources.getInstance(graph); + DiagramResource DIA = DiagramResource.getInstance(graph); + Layer0 L0 = Layer0.getInstance(graph); + return parameter.stream().collect(Collectors.toMap(p -> p, p -> { + try { + if (p instanceof Resource) { + Resource element = (Resource) p; + if (graph.isInstanceOf(element, DIA.Element)) { + Resource component = graph.getPossibleObject(element, MOD.ElementToComponent); + if (component != null) { + GUID identifier = graph.getPossibleRelatedValue(component, L0.identifier, GUID.BINDING); + if (identifier != null) { + return Arrays.toString(createURIBasedL0Identifier(graph, component)); + } else { + LOGGER.error("Component {} does not have GUID identifier!", component); + } + } else if (graph.isInstanceOf(element, DIA.Connection) || graph.isInstanceOf(element, DIA.Terminal)) { + // Ok, lets create a hashcode for connections and terminals as they do not have identifiers + return graph.getURI(element).hashCode(); + } else { + // Ok, lets create a hashcode or either return empty string in cases where no ID is required + if (graph.hasStatement(element, L0.HasName)) + return graph.getURI(element).hashCode(); + return ""; + } + } + } else { + LOGGER.error("Parameter p {} is not resource but it is {}", p, p.getClass()); + } + return p; + } catch (DatabaseException e) { + throw new RuntimeDatabaseException(e); + } + })); + } + }); + } catch (DatabaseException e) { + LOGGER.error("Could not apply mappings", e); + throw new RuntimeDatabaseException(e); + } + } + }); + } + + private static String renderSVG0(ICanvasContext ctx, Function1, Map> mappingFunction) { // Get a DOMImplementation. DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation(); @@ -495,166 +596,14 @@ public class SCLScenegraph { result.append(""); - IG2DNodeVisitor visitor = new IG2DNodeVisitor() { - - int indent = 0; - - HashMap senBuilders = new HashMap<>(); - - @Override - public void enter(IG2DNode node) { - - StringBuilder parentBuilder = getParentBuilder(node); - - indent++; - if(node instanceof ConnectionNode) { - - for(RouteGraphNode n : NodeUtil.collectNodes(node, RouteGraphNode.class)) { - n.setIgnoreSelection(true); - } - - String key = ((ConnectionNode)node).getKey().toString(); - - parentBuilder.append("\n"); - Element doc = renderSVGNode((IG2DNode)node); - String svg = printSVGDocument(doc); - parentBuilder.append(svg); - - for(RouteGraphNode n : NodeUtil.collectNodes(node, RouteGraphNode.class)) { - n.setIgnoreSelection(false); - } - - parentBuilder.append("\n"); - doc = renderSVGNode((IG2DNode)node); - svg = printSVGDocument(doc); - parentBuilder.append(svg); - parentBuilder.append("\n"); - - BasicStroke bs = new BasicStroke(5f); - - for(RouteGraphNode n : NodeUtil.collectNodes(node, RouteGraphNode.class)) { - n.setDynamicStroke(bs); - } - - parentBuilder.append("\n"); - doc = renderSVGNode((IG2DNode)node); - svg = printSVGDocument(doc); - parentBuilder.append(svg); - parentBuilder.append("\n"); - - parentBuilder.append("\n"); - - } else if (node instanceof SelectionNode) { - - SelectionNode n = (SelectionNode)node; - SingleElementNode parentSEN = (SingleElementNode)NodeUtil.getNearestParentOfType(node, SingleElementNode.class); - if(parentSEN != null && parentSEN.getKey() != null) { - - StringBuilder parentBuilder2 = getParentBuilder(parentSEN); - - String key = parentSEN.getKey().toString(); - Element doc = renderSVGNode((IG2DNode)node); - String svg = printSVGDocument(doc); - parentBuilder2.append("\n"); - parentBuilder2.append(svg); - parentBuilder2.append("\n"); - parentBuilder2.append("\n"); - Rectangle2D rect = n.getRect(); - parentBuilder2.append(""); - parentBuilder2.append("\n"); - } - } else if (node instanceof SVGNode) { - SVGNode svg = (SVGNode)node; - parentBuilder.append(svg.getSVGText()); - } else if (node instanceof G2DParentNode) { - AffineTransform at = node.getTransform(); - if(node instanceof SingleElementNode) { - SingleElementNode sen = (SingleElementNode)node; - if(sen.getKey() != null) { - String key = sen.getKey().toString(); - parentBuilder.append("\n"); - } - senBuilders.put(sen, new StringBuilder()); - } - if(!at.isIdentity()) { - if(at.getScaleX() == 1.0 && at.getScaleY() == 1.0 && at.getShearX() == 0.0 && at.getShearY() == 0.0) { - String m = "translate(" + at.getTranslateX() + " " + at.getTranslateY() + ")"; - parentBuilder.append("\n"); - } else { - double[] ds = new double[6]; - at.getMatrix(ds); - String m = "matrix(" + ds[0] + " " + ds[1] + " " + ds[2] + " " + ds[3] + " " + ds[4] + " " + ds[5] + ")"; - parentBuilder.append("\n"); - } - } - } - - //enters.put(node, b.length()); - - } - - private StringBuilder getParentBuilder(IG2DNode node) { - - INode parentSEN = NodeUtil.getNearestParentOfType(node, SingleElementNode.class); - if(parentSEN instanceof G2DSceneGraph) return result; - - StringBuilder parentBuilder = senBuilders.get(parentSEN); - if(parentBuilder == null) return result; - - return parentBuilder; - - } - - @Override - public void leave(IG2DNode node) { - - if(node instanceof ConnectionNode || node instanceof SVGNode) { - // We are done - } else if (node instanceof G2DParentNode) { - - StringBuilder parentBuilder = getParentBuilder(node); - - if(node instanceof SingleElementNode) { - SingleElementNode sen = (SingleElementNode)node; -// if(sen.getKey() != null) { - StringBuilder b = senBuilders.get(sen); - String content = b.toString(); - if(content.isEmpty()) { - if(sen.getKey() != null) { - - for(SelectionNode n : NodeUtil.collectNodes(node, SelectionNode.class)) { - n.setIgnore(true); - } - - Element doc = renderSVGNode((IG2DNode)node); - String svg = printSVGDocument(doc); - parentBuilder.append(svg); - } - } else { - parentBuilder.append(content); - } -// } - } - - - AffineTransform at = node.getTransform(); - if(!at.isIdentity()) { - parentBuilder.append(""); - } - if(node instanceof SingleElementNode) { - SingleElementNode sen = (SingleElementNode)node; - if(sen.getKey() != null) { - parentBuilder.append(""); - } - } - } - indent --; - } + KeyVisitor keyVisitor = new KeyVisitor(); + sg.accept(keyVisitor); + + Set keys = keyVisitor.getKeys(); + + Map mappings = mappingFunction.apply(keys); - }; + IG2DNodeVisitor visitor = new PrintingVisitor(result, mappings); sg.accept(visitor); } catch (Throwable t) { @@ -665,8 +614,208 @@ public class SCLScenegraph { //System.err.println(" == FINAL RESULT == "); //System.err.println(b); return result.toString(); + } + + + + private static class KeyVisitor implements IG2DNodeVisitor { + + private Set keys = new HashSet<>(); + @Override + public void enter(IG2DNode node) { + if (node instanceof SingleElementNode) { + Object key = ((SingleElementNode) node).getKey(); + if (key != null) { + keys.add(key); + } + } + } + + @Override + public void leave(IG2DNode node) { + // Nothing to do + } + + public Set getKeys() { + return keys; + } } + private static class PrintingVisitor implements IG2DNodeVisitor { + + int indent = 0; + + HashMap senBuilders = new HashMap<>(); + + private StringBuilder result; + + private Map mappings; + + public PrintingVisitor(StringBuilder result, Map mappings) { + this.result = result; + this.mappings = mappings; + } + + private String getKey(SingleElementNode node) { + String key; + if (mappings.containsKey(node.getKey())) + key = mappings.get(node.getKey()).toString(); + else + key = node.getKey().toString(); + return key; + } + + @Override + public void enter(IG2DNode node) { + + StringBuilder parentBuilder = getParentBuilder(node); + + indent++; + if(node instanceof ConnectionNode) { + + for(RouteGraphNode n : NodeUtil.collectNodes(node, RouteGraphNode.class)) { + n.setIgnoreSelection(true); + } + + String key = getKey((ConnectionNode) node); + parentBuilder.append("\n"); + Element doc = renderSVGNode((IG2DNode)node); + String svg = printSVGDocument(doc); + parentBuilder.append(svg); + + for(RouteGraphNode n : NodeUtil.collectNodes(node, RouteGraphNode.class)) { + n.setIgnoreSelection(false); + } + + parentBuilder.append("\n"); + doc = renderSVGNode((IG2DNode)node); + svg = printSVGDocument(doc); + parentBuilder.append(svg); + parentBuilder.append("\n"); + + BasicStroke bs = new BasicStroke(5f); + + for(RouteGraphNode n : NodeUtil.collectNodes(node, RouteGraphNode.class)) { + n.setDynamicStroke(bs); + } + + parentBuilder.append("\n"); + doc = renderSVGNode((IG2DNode)node); + svg = printSVGDocument(doc); + parentBuilder.append(svg); + parentBuilder.append("\n"); + + parentBuilder.append("\n"); + + } else if (node instanceof SelectionNode) { + + SelectionNode n = (SelectionNode)node; + SingleElementNode parentSEN = (SingleElementNode)NodeUtil.getNearestParentOfType(node, SingleElementNode.class); + if(parentSEN != null && parentSEN.getKey() != null) { + + StringBuilder parentBuilder2 = getParentBuilder(parentSEN); + + String key = getKey(parentSEN); + Element doc = renderSVGNode((IG2DNode)node); + String svg = printSVGDocument(doc); + parentBuilder2.append("\n"); + parentBuilder2.append(svg); + parentBuilder2.append("\n"); + parentBuilder2.append("\n"); + Rectangle2D rect = n.getRect(); + parentBuilder2.append(""); + parentBuilder2.append("\n"); + } + } else if (node instanceof SVGNode) { + SVGNode svg = (SVGNode)node; + parentBuilder.append(svg.getSVGText()); + } else if (node instanceof G2DParentNode) { + AffineTransform at = node.getTransform(); + if(node instanceof SingleElementNode) { + SingleElementNode sen = (SingleElementNode)node; + if(sen.getKey() != null) { + String key = getKey(sen); + parentBuilder.append("\n"); + } + senBuilders.put(sen, new StringBuilder()); + } + if(!at.isIdentity()) { + if(at.getScaleX() == 1.0 && at.getScaleY() == 1.0 && at.getShearX() == 0.0 && at.getShearY() == 0.0) { + String m = "translate(" + at.getTranslateX() + " " + at.getTranslateY() + ")"; + parentBuilder.append("\n"); + } else { + double[] ds = new double[6]; + at.getMatrix(ds); + String m = "matrix(" + ds[0] + " " + ds[1] + " " + ds[2] + " " + ds[3] + " " + ds[4] + " " + ds[5] + ")"; + parentBuilder.append("\n"); + } + } + } + + //enters.put(node, b.length()); + + } + + private StringBuilder getParentBuilder(IG2DNode node) { + + INode parentSEN = NodeUtil.getNearestParentOfType(node, SingleElementNode.class); + if(parentSEN instanceof G2DSceneGraph) return result; + + StringBuilder parentBuilder = senBuilders.get(parentSEN); + if(parentBuilder == null) return result; + + return parentBuilder; + + } + @Override + public void leave(IG2DNode node) { + + if(node instanceof ConnectionNode || node instanceof SVGNode) { + // We are done + } else if (node instanceof G2DParentNode) { + + StringBuilder parentBuilder = getParentBuilder(node); + + if(node instanceof SingleElementNode) { + SingleElementNode sen = (SingleElementNode)node; +// if(sen.getKey() != null) { + StringBuilder b = senBuilders.get(sen); + String content = b.toString(); + if(content.isEmpty()) { + if(sen.getKey() != null) { + + for(SelectionNode n : NodeUtil.collectNodes(node, SelectionNode.class)) { + n.setIgnore(true); + } + + Element doc = renderSVGNode((IG2DNode)node); + String svg = printSVGDocument(doc); + parentBuilder.append(svg); + } + } else { + parentBuilder.append(content); + } +// } + } + + + AffineTransform at = node.getTransform(); + if(!at.isIdentity()) { + parentBuilder.append(""); + } + if(node instanceof SingleElementNode) { + SingleElementNode sen = (SingleElementNode)node; + if(sen.getKey() != null) { + parentBuilder.append(""); + } + } + } + indent --; + } + } } \ No newline at end of file diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/adapters/CompositeCopyHandler.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/adapters/CompositeCopyHandler.java index ae65e87f8..6167334fd 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/adapters/CompositeCopyHandler.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/adapters/CompositeCopyHandler.java @@ -22,6 +22,7 @@ import org.simantics.db.Resource; import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.common.request.PossibleIndexRoot; import org.simantics.db.exception.DatabaseException; +import org.simantics.db.function.DbConsumer; import org.simantics.db.layer0.adapter.SubgraphExtent.ExtentStatus; import org.simantics.db.layer0.adapter.impl.DefaultCopyHandler; import org.simantics.db.layer0.util.TransferableGraphConfiguration2; @@ -64,39 +65,63 @@ public class CompositeCopyHandler extends DefaultCopyHandler { if(indexRoot == null) throw new DatabaseException("Composite is not part of any index root"); String indexRootUri = graph.getURI(indexRoot); + DbConsumer identifierExcluder = r -> { + if (r != null) + exclusions.addAll(graph.getObjects(r, L0.identifier)); + }; + for(Resource resource : resources) { // Process all connection joins. // This is the only way to access all of them. for (Resource diagram : graph.getObjects(resource, MOD.CompositeToDiagram)) { - for (Resource flag : graph.syncRequest(new ObjectsWithType(diagram, L0.ConsistsOf, DIA.Flag))) { - for (Resource join : graph.getObjects(flag, DIA.FlagIsJoinedBy)) { - // Joins with external references are omitted - for (Resource comp : graph.getObjects(join, SR.JoinsComposite)) { - if (!resourceSet.contains(comp)) - exclusions.add(join); - } - // This code excludes joins with flags to external - // diagrams that are not connected (have no - // configuration for the flag) - for (Resource flag2 : graph.getObjects(join, DIA.JoinsFlag)) { - Resource diagram2 = graph.getPossibleObject(flag2, L0.PartOf); - if (diagram2 != null) { - Resource comp = graph.getPossibleObject(diagram2, MOD.DiagramToComposite); + identifierExcluder.accept(diagram); + + for (Resource element : graph.getObjects(diagram, L0.ConsistsOf)) { + identifierExcluder.accept(element); + + Set types = graph.getTypes(element); + + // Check all diagram flag elements for necessary exclusions. + if (types.contains(DIA.Flag)) { + for (Resource join : graph.getObjects(element, DIA.FlagIsJoinedBy)) { + // Joins with external references are omitted + for (Resource comp : graph.getObjects(join, SR.JoinsComposite)) { if (!resourceSet.contains(comp)) - exclusions.add(join); + exclusions.add(join); + } + // This code excludes joins with flags to external + // diagrams that are not connected (have no + // configuration for the flag) + for (Resource flag2 : graph.getObjects(join, DIA.JoinsFlag)) { + Resource diagram2 = graph.getPossibleObject(flag2, L0.PartOf); + if (diagram2 != null) { + Resource comp = graph.getPossibleObject(diagram2, MOD.DiagramToComposite); + if (!resourceSet.contains(comp)) + exclusions.add(join); + } + } + } + } + + // Check all diagram monitor elements. + // Any components referenced that are external to the exported diagrams must be excluded from the export. + // This will leave the monitors without a monitored component but export and import will work anyway. + if (types.contains(DIA.Monitor)) { + for (Resource monitoredComponent : graph.getObjects(element, DIA.HasMonitorComponent)) { + Resource monitoredComponentComposite = graph.getPossibleObject(monitoredComponent, L0.PartOf); + if (monitoredComponentComposite != null && !resourceSet.contains(monitoredComponentComposite)) { + exclusions.add(monitoredComponent); } } } - } - // Check all diagram monitor elements. - // Any components referenced that are external to the exported diagrams must be excluded from the export. - // This will leave the monitors without a monitored component but export and import will work anyway. - for (Resource ref : graph.syncRequest(new ObjectsWithType(diagram, L0.ConsistsOf, DIA.Monitor))) { - for (Resource monitoredComponent : graph.getObjects(ref, DIA.HasMonitorComponent)) { - Resource monitoredComponentComposite = graph.getPossibleObject(monitoredComponent, L0.PartOf); - if (monitoredComponentComposite != null && !resourceSet.contains(monitoredComponentComposite)) { - exclusions.add(monitoredComponent); + // Check all diagram reference elements for necessary exclusions. + if (types.contains(MOD.ReferenceElement)) { + for (Resource rel : graph.getObjects(element, L0.ConsistsOf)) { + identifierExcluder.accept(rel); + for (Resource invRel : graph.getObjects(rel, L0.ConsistsOf)) { + identifierExcluder.accept(invRel); + } } } } @@ -119,13 +144,11 @@ public class CompositeCopyHandler extends DefaultCopyHandler { // Include resource as root CompositeInfo info = CompositeInfo.fromResource(graph, resource); roots.add(new RootSpec(resource, info.getTGName(), true, typeId(graph, L0, indexRootUri, resource))); - Resource id = graph.getPossibleObject(resource, L0.identifier); - if(id != null) exclusions.add(id); + identifierExcluder.accept(resource); // Include components as roots - for(Resource child : graph.sync(new ObjectsWithType(resource, L0.ConsistsOf, SR.Component))) { - DiagramComponentInfo cinfo = DiagramComponentInfo.fromResource(graph, info, child); - id = graph.getPossibleObject(child, L0.identifier); - if(id != null) exclusions.add(id); + for (Resource child : graph.sync(new ObjectsWithType(resource, L0.ConsistsOf, SR.Component))) { + DiagramComponentInfo cinfo = DiagramComponentInfo.fromResource(graph, info, child); + identifierExcluder.accept(child); roots.add(new RootSpec(child, cinfo.getTGName(info), true, typeId(graph, L0, indexRootUri, child))); } } diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/ComponentCopyAdvisor.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/ComponentCopyAdvisor.java index 96aa3f134..6b4e59d17 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/ComponentCopyAdvisor.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/ComponentCopyAdvisor.java @@ -17,7 +17,6 @@ import java.util.Map; import org.simantics.Simantics; import org.simantics.databoard.Bindings; -import org.simantics.datatypes.literal.GUID; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; import org.simantics.db.exception.DatabaseException; @@ -74,7 +73,7 @@ public class ComponentCopyAdvisor extends GraphCopyAdvisor { if (graph.hasStatement(sourceContainer, L0.ConsistsOf, source)) graph.claim(targetContainer, L0.ConsistsOf, copy); - Layer0Utils.addL0Identifier(graph, copy); + Layer0Utils.claimNewIdentifier(graph, copy, false); if (context.get(SynchronizationHints.NO_RENAME) == null) renameComponent(context, graph, source, copy, sourceContainer, targetContainer); return copy; diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/ElementCopyAdvisor.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/ElementCopyAdvisor.java index 994aa1ab1..d666d63d5 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/ElementCopyAdvisor.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/ElementCopyAdvisor.java @@ -23,6 +23,7 @@ import org.simantics.db.common.utils.OrderedSetUtils; import org.simantics.db.exception.CancelTransactionException; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.request.PossibleModel; +import org.simantics.db.layer0.util.Layer0Utils; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.diagram.stubs.G2DResource; import org.simantics.diagram.synchronization.ISynchronizationContext; @@ -89,6 +90,8 @@ public class ElementCopyAdvisor extends GraphCopyAdvisor { if (graph.hasStatement(sourceContainer, L0.ConsistsOf, source)) graph.claim(targetContainer, L0.ConsistsOf, copy); + Layer0Utils.claimNewIdentifier(graph, copy, false); + return copy; } diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/NamingCreationInstruction.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/NamingCreationInstruction.java index 3330587b9..0796e6879 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/NamingCreationInstruction.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/NamingCreationInstruction.java @@ -14,7 +14,6 @@ package org.simantics.modeling.mapping; import gnu.trove.map.hash.TIntIntHashMap; import gnu.trove.set.hash.TIntHashSet; -import org.simantics.datatypes.literal.GUID; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; import org.simantics.db.common.utils.CommonDBUtils; @@ -55,7 +54,7 @@ public class NamingCreationInstruction extends CreationInstruction { Resource result = GraphUtils.create(g, b.HasName, proposition ); - Layer0Utils.addL0Identifier(g, result); + Layer0Utils.claimNewIdentifier(g, result, true); return result; } catch (NamingException e1) { throw new DatabaseException(e1); diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/utils/OntologicalRequirementEnforceRequest.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/utils/OntologicalRequirementEnforceRequest.java index 905305bc3..dd547ffe3 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/utils/OntologicalRequirementEnforceRequest.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/utils/OntologicalRequirementEnforceRequest.java @@ -2,7 +2,6 @@ package org.simantics.modeling.utils; import java.util.Collection; -import org.simantics.datatypes.literal.GUID; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; import org.simantics.db.common.CommentMetadata; @@ -113,7 +112,7 @@ public class OntologicalRequirementEnforceRequest extends WriteRequest { for (Resource r : ids) { if (!graph.hasStatement(r, L0.identifier)) { CommonDBUtils.selectClusterSet(graph, r); - Layer0Utils.addL0Identifier(graph, r); + Layer0Utils.claimNewIdentifier(graph, r, true); } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/SCLConstant.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/SCLConstant.java index 14bcbcaf6..9089ebb81 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/SCLConstant.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/SCLConstant.java @@ -373,4 +373,11 @@ public class SCLConstant extends DelegateConstant implements Named { if(inlineArity < Integer.MAX_VALUE) inlinableDefinition = (SSAFunction)definition.copy(); } + + public void cleanup() { + if(definition != null) + definition.cleanup(); + if(inlinableDefinition != null) + inlinableDefinition.cleanup(); + } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRLiteral.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRLiteral.java index 7b4a5bc26..f44609e6c 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRLiteral.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRLiteral.java @@ -47,6 +47,10 @@ public class CHRLiteral extends Symbol { } public void resolve(TranslationContext context) { + if(parameters != null) { + for(int i=0;i allRefs, TIntHashSet refs) { diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/StandardExpressionTransformer.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/StandardExpressionTransformer.java index ac61eb486..1bd0d22c4 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/StandardExpressionTransformer.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/StandardExpressionTransformer.java @@ -9,6 +9,7 @@ import org.simantics.scl.compiler.elaboration.equation.Equation; import org.simantics.scl.compiler.elaboration.equation.EquationVisitor; import org.simantics.scl.compiler.elaboration.expressions.accessor.ExpressionAccessor; import org.simantics.scl.compiler.elaboration.expressions.block.BindStatement; +import org.simantics.scl.compiler.elaboration.expressions.block.CHRStatement; import org.simantics.scl.compiler.elaboration.expressions.block.GuardStatement; import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement; import org.simantics.scl.compiler.elaboration.expressions.block.LetStatement; @@ -517,4 +518,12 @@ EquationVisitor { equation.guard = equation.guard.accept(this); } + @Override + public void visit(CHRStatement statement) { + for(int i=0;i classes = moduleBuilder.getClasses(); + ssaModule.cleanup(); // Load generated code and execute try { diff --git a/bundles/org.simantics.structural2/src/org/simantics/structural2/utils/StructuralUtils.java b/bundles/org.simantics.structural2/src/org/simantics/structural2/utils/StructuralUtils.java index 9b9dc6cb6..9a77d100f 100644 --- a/bundles/org.simantics.structural2/src/org/simantics/structural2/utils/StructuralUtils.java +++ b/bundles/org.simantics.structural2/src/org/simantics/structural2/utils/StructuralUtils.java @@ -7,7 +7,6 @@ import java.util.List; import java.util.Set; import org.simantics.databoard.Bindings; -import org.simantics.datatypes.literal.GUID; import org.simantics.db.ReadGraph; import org.simantics.db.RequestProcessor; import org.simantics.db.Resource; @@ -142,8 +141,7 @@ public class StructuralUtils { g.claim(component, L0.HasName, Layer0Utils.literal(g, name)); g.claim(component, L0.HasLabel, Layer0Utils.literal(g, "")); g.claim(parent, L0.ConsistsOf, component); - // Add identifier - Layer0Utils.addL0Identifier(g, component); + Layer0Utils.claimNewIdentifier(g, component, true); // Add comment to change set. CommentMetadata cm = g.getMetadata(CommentMetadata.class); g.addMetadata(cm.add("Created component " + component)); diff --git a/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/utils/ModelledSTSTest.java b/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/utils/ModelledSTSTest.java index 94ff2b6b6..e1eb08baf 100644 --- a/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/utils/ModelledSTSTest.java +++ b/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/utils/ModelledSTSTest.java @@ -102,22 +102,22 @@ public class ModelledSTSTest { ModuleRepository repo = new ModuleRepository(SCLOsgi.SOURCE_REPOSITORY); CommandSession session = null; try { - repo.setAdvisor(new ModuleCompilationOptionsAdvisor() { - - @Override - public ModuleCompilationOptions getOptions(String moduleName) { - // TODO: default to false - boolean coverage = true; - // TODO: add moduleName filters back - // for (Pattern p : getModuleNameFilterPatterns()) { - // if (p.matcher(moduleName.toLowerCase()).find()) { - // coverage = true; - // break; - // } - // } - return new ModuleCompilationOptions(coverage); - } - }); +// repo.setAdvisor(new ModuleCompilationOptionsAdvisor() { +// +// @Override +// public ModuleCompilationOptions getOptions(String moduleName) { +// // TODO: default to false +// boolean coverage = true; +// // TODO: add moduleName filters back +// // for (Pattern p : getModuleNameFilterPatterns()) { +// // if (p.matcher(moduleName.toLowerCase()).find()) { +// // coverage = true; +// // break; +// // } +// // } +// return new ModuleCompilationOptions(coverage); +// } +// }); SCLReportingHandler handler = (SCLReportingHandler) SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER); session = new CommandSession(repo, handler); diff --git a/bundles/org.simantics.ui/src/org/simantics/ui/workbench/ResourceEditorSupport.java b/bundles/org.simantics.ui/src/org/simantics/ui/workbench/ResourceEditorSupport.java index 4075e1e11..80e0393cf 100644 --- a/bundles/org.simantics.ui/src/org/simantics/ui/workbench/ResourceEditorSupport.java +++ b/bundles/org.simantics.ui/src/org/simantics/ui/workbench/ResourceEditorSupport.java @@ -311,7 +311,9 @@ public class ResourceEditorSupport implements IAdaptable, ChangeListener { } private static void scheduleEditorClose(IEditorPart editorPart) { - SWTUtils.asyncExec(editorPart.getSite().getShell(), () -> { + if (editorPart == null) + return; + SWTUtils.asyncExec(editorPart.getSite().getWorkbenchWindow().getShell(), () -> { // Don't have to check isDisposed since closeEditor // will ignore already closed editor parts. WorkbenchUtils.closeEditor(editorPart, false); diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/MemoryLeakTest.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/MemoryLeakTest.java new file mode 100644 index 000000000..7ff61a83e --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/MemoryLeakTest.java @@ -0,0 +1,74 @@ +package org.simantics.scl.compiler.tests; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.simantics.scl.compiler.environment.specification.EnvironmentSpecification; +import org.simantics.scl.compiler.errors.CompilationErrorFormatter; +import org.simantics.scl.compiler.module.repository.ImportFailure; +import org.simantics.scl.compiler.module.repository.ImportFailureException; +import org.simantics.scl.compiler.module.repository.ModuleRepository; +import org.simantics.scl.compiler.runtime.RuntimeEnvironment; +import org.simantics.scl.compiler.top.ExpressionEvaluator; +import org.simantics.scl.compiler.top.SCLExpressionCompilationException; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; + +public class MemoryLeakTest { + ModuleRepository moduleRepository; + + EnvironmentSpecification environmentSpecification; + + @Before + public void initialize() throws Exception { + moduleRepository = InitialRepository.getInitialRepository(); + + // Environment for compiling expressions + environmentSpecification = new EnvironmentSpecification(); + environmentSpecification.importModule("Builtin", ""); + environmentSpecification.importModule("Prelude", ""); + } + + private void testExpression0(String expressionText, + Object expectedValue, + Type expectedType) throws Exception { + + RuntimeEnvironment runtimeEnvironment; + try { + runtimeEnvironment = moduleRepository.createRuntimeEnvironment(environmentSpecification, + getClass().getClassLoader()); + } catch(ImportFailureException e) { + for(ImportFailure failure : e.failures) + System.err.println("Failed to import " + failure.moduleName); + throw e; + } + + // Compiling and running expression + try { + Object result = new ExpressionEvaluator(runtimeEnvironment, expressionText) + .expectedType(expectedType) + .interpretIfPossible(false) + .eval(); + if(expectedValue != null) + Assert.assertEquals(expectedValue, result); + } catch(SCLExpressionCompilationException e) { + System.out.println(CompilationErrorFormatter.toString(expressionText, e.getErrors())); + throw e; + } + } + + @Test + public void testIt() throws Exception { + for(int i=0;i<1000000;++i) { + testExpression0("fst (\"a\", \"b\")", "a", Types.STRING); + if(i % 10000 == 0 && i > 0) { + System.gc(); + System.runFinalization(); + System.gc(); + Thread.sleep(100L); + double used = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()); + System.out.println(i + " " + used*1e-6 + " Mb, " + (used / i) + " b / expression"); + } + } + } +}