1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.impl;
14 import java.io.Closeable;
16 import java.io.IOException;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.Collection;
20 import java.util.HashSet;
21 import java.util.LinkedList;
22 import java.util.function.Consumer;
24 import org.simantics.databoard.Bindings;
25 import org.simantics.databoard.binding.Binding;
26 import org.simantics.databoard.serialization.SerializationException;
27 import org.simantics.databoard.serialization.Serializer;
28 import org.simantics.databoard.serialization.SerializerConstructionException;
29 import org.simantics.db.AsyncReadGraph;
30 import org.simantics.db.AsyncRequestProcessor;
31 import org.simantics.db.Resource;
32 import org.simantics.db.Statement;
33 import org.simantics.db.VirtualGraphContext;
34 import org.simantics.db.VirtualGraphSource;
35 import org.simantics.db.WriteGraph;
36 import org.simantics.db.WriteOnlyGraph;
37 import org.simantics.db.common.ByteFileReader;
38 import org.simantics.db.common.ByteFileWriter;
39 import org.simantics.db.common.StandardStatement;
40 import org.simantics.db.common.request.WriteOnlyRequest;
41 import org.simantics.db.common.request.WriteRequest;
42 import org.simantics.db.common.utils.Logger;
43 import org.simantics.db.exception.DatabaseException;
44 import org.simantics.db.impl.graph.ReadGraphImpl;
45 import org.simantics.db.impl.support.ResourceSupport;
46 import org.simantics.db.impl.support.VirtualGraphServerSupport;
47 import org.simantics.db.procedure.AsyncProcedure;
48 import org.simantics.db.request.Write;
49 import org.simantics.db.request.WriteOnly;
50 import org.simantics.db.service.SerialisationSupport;
52 import gnu.trove.list.array.TIntArrayList;
53 import gnu.trove.map.hash.TIntObjectHashMap;
54 import gnu.trove.procedure.TIntObjectProcedure;
55 import gnu.trove.procedure.TIntProcedure;
56 import gnu.trove.set.hash.TIntHashSet;
58 class VirtualCluster {
59 static final boolean DEBUG = false;
60 final static int[] EMPTY = new int[0];
62 private final ArrayList<TIntArrayList> statements = new ArrayList<TIntArrayList>();
63 private final TIntHashSet lazy = new TIntHashSet();
64 private final TIntObjectHashMap<byte[]> values = new TIntObjectHashMap<byte[]>();
65 private final int clusterId;
67 public VirtualCluster(int clusterId) {
68 this.clusterId = clusterId;
71 public int clusterId() {
78 private TIntArrayList getPredicateMap(int subject) {
80 int rId = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(subject);
81 if(rId >= statements.size()) return null;
82 return statements.get(rId);
86 public boolean isPending(int subject) {
87 return lazy.contains(subject);
90 boolean containsPredicate(TIntArrayList statements, int predicate) {
91 for(int i=0;i<statements.size();i+=2) if(statements.getQuick(i) == predicate) return true;
95 int containsStatement(TIntArrayList statements, int predicate, int object) {
96 for(int i=0;i<statements.size();i+=2) if(statements.getQuick(i) == predicate && statements.getQuick(i+1) == object) return i;
100 public boolean isPending(int subject, int predicate) {
102 if(!lazy.contains(subject)) return false;
103 TIntArrayList predicateMap = getPredicateMap(subject);
104 if(predicateMap == null) return true;
105 return !containsPredicate(predicateMap, predicate);
106 // return !predicateMap.contains(predicate);
110 public void resetLazy(int subject) {
112 lazy.remove(subject);
113 // Query all data from scratch
114 int ri = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(subject);
115 statements.set(ri, new TIntArrayList());
119 public void setLazy(int subject) {
125 public void finish(int subject) {
127 lazy.remove(subject);
131 public void setValue(int subject, byte[] data, int length) {
133 values.put(subject, Arrays.copyOf(data, length));
137 public void denyValue(int subject) {
139 values.remove(subject);
143 public void addStatements(int subject, int[] data) {
145 TIntArrayList result = getPredicateMap(subject);
147 result = new TIntArrayList();
148 int rId = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(subject);
149 statements.ensureCapacity(rId+1);
150 for(int i=statements.size();i<rId+1;i++) statements.add(null);
151 statements.set(rId, result);
154 for(int i=0;i<data.length;i+=2) {
155 int predicate = data[i];
156 int object = data[i+1];
157 if(containsStatement(result, predicate, object) < 0) {
158 result.add(predicate);
165 public void claim(int subject, int predicate, int object) {
167 TIntArrayList predicates = getPredicateMap(subject);
168 if(predicates == null) {
169 predicates = new TIntArrayList();
170 int rId = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(subject);
171 statements.ensureCapacity(rId+1);
172 for(int i=statements.size();i<rId+1;i++) statements.add(null);
173 statements.set(rId, predicates);
176 if(containsStatement(predicates, predicate, object) < 0) {
177 predicates.add(predicate);
178 predicates.add(object);
183 public void deny(int subject, int predicate, int object) {
185 TIntArrayList predicates = getPredicateMap(subject);
186 if(predicates == null) return;
187 int index = containsStatement(predicates, predicate, object);
188 if(index < 0) return;
189 predicates.remove(index, 2);
193 int[] getObjects(int subject, int predicate) {
195 TIntArrayList predicates = getPredicateMap(subject);
196 if(predicates == null) return EMPTY;
197 TIntArrayList result = new TIntArrayList();
198 for(int i=0;i<predicates.size();i+=2) {
199 if(predicates.getQuick(i) == predicate) {
200 result.add(predicates.getQuick(i+1));
203 return result.toArray();
207 int[] getPredicates(int subject) {
209 TIntArrayList predicates = getPredicateMap(subject);
210 if(predicates == null) return EMPTY;
211 TIntHashSet result = new TIntHashSet();
212 for(int i=0;i<predicates.size();i+=2) {
213 result.add(predicates.getQuick(i));
215 return result.toArray();
219 byte[] getValue(int subject) {
220 return values.get(subject);
223 public int getTransientClusterKey() {
224 int clusterBits = ClusterTraitsBase.getClusterBits(clusterId>>>1);
225 if((clusterId & 1) == 0) // Virtual subjects
226 return clusterBits | 0x80000000; // We are assuming that MSB means virtual resource.
227 else // Database subjects
231 public int getTransientId(int subject) {
232 if((clusterId & 1) == 0) // Virtual subjects
233 return ClusterTraitsBase.createResourceKeyNoThrow(clusterId>>1, subject) | 0x80000000;
234 else // Database subjects
235 return ClusterTraitsBase.createResourceKeyNoThrow(clusterId>>1, subject);
239 * Creates a persistent identifier for given transient graph cluster identifier.
242 * For persistent clusters this obtains the random access id for (invalid)
243 * resource at index 0 of given cluster. LSB in given id indicates persistence
248 public static long getClusterIdentifier(SerialisationSupport ss, int clusterKey) {
249 if((clusterKey & 1) == 0)// Virtual subjects
251 else { // Database subjects
252 int rk = ClusterTraitsBase.createResourceKeyNoThrow(clusterKey>>1, 1);
254 // Assuming that cluster's first resource is created first and not deleted.
255 // Assuming that resource index is in LSB bits.
256 return ss.getRandomAccessId(rk);
257 } catch (DatabaseException e) {
258 Logger.defaultLogError("Could not get cluster id for virtual cluster key=" + clusterKey, e);
264 public void saveImpl(final File file, SerialisationSupport ss) throws IOException {
266 System.out.println("DEBUG: Saving virtual cluster " + clusterId + " to " + file.getAbsolutePath());
268 final ByteFileWriter writer = new ByteFileWriter(file);
273 for(TIntArrayList list : statements) {
278 writer.write((int)(1.5*stms));
279 @SuppressWarnings("unused")
281 for(int i=0;i<statements.size();i++) {
282 TIntArrayList list = statements.get(i);
284 for(int j=0;j<list.size();j+=2) {
286 writer.write((short)i);
287 int rk = list.getQuick(j);
288 long rid = ss.getRandomAccessId(rk);
290 rk = list.getQuick(j+1);
291 rid = ss.getRandomAccessId(rk);
294 } catch (DatabaseException e) {
301 writer.write(values.size());
303 values.forEachEntry(new TIntObjectProcedure<byte[]>() {
306 public boolean execute(int a, byte[] b) {
308 writer.write(b.length);
314 System.out.println("TransientGraph[" + file.getAbsolutePath() + "] wrote " + count + " statements and " + values.size() + " values to disk.");
318 // FileUtils.uncheckedClose(_os);
322 public void load(File file, SerialisationSupport serialization, VirtualGraphServerSupport vgss) throws DatabaseException {
324 System.out.println("DEBUG: Loading virtual cluster " + clusterId + " from " + file.getAbsolutePath() + " " + file.length());
326 ByteFileReader reader = null;
332 reader = new ByteFileReader(file);
333 int clusterInt = ClusterTraitsBase.getClusterBits(clusterId()>>1);
334 int stms = reader.readInt();
335 for (int i = 0; i < stms; i += 3) {
336 // int rId = reader.readShort();
337 // if(vgss != null) vgss.addVirtual(clusterInt + rId);
339 // serialization.getTransientId(reader.readLong()),
340 // serialization.getTransientId(reader.readLong()));
341 int rId = reader.readShort();
342 long sId = reader.readLong();
343 long oId = reader.readLong();
344 int sTransientId = serialization.getTransientId(sId);
345 int oTransientId = serialization.getTransientId(oId);
348 vgss.addVirtual(clusterInt + rId);
350 claim(rId, sTransientId, oTransientId);
353 int values = reader.readInt();
354 for (int i = 0; i < values; i++) {
355 int subject = reader.readInt();
356 int length = reader.readInt();
357 setValue(subject, reader.readBytes(length), length);
360 System.out.println("DEBUG: TransientGraph[" + file.getAbsolutePath() + "] loaded " + stms / 3 + " statements and " + values + " values from disk.");
362 } catch (IOException e) {
363 throw new DatabaseException(e);
370 void listStatements(SerialisationSupport ss, ArrayList<Statement> result) {
372 int clusterKey = getTransientClusterKey();
375 for(int i=0;i<statements.size();i++) {
376 TIntArrayList list = statements.get(i);
378 Resource subject = ss.getResource(clusterKey | i);
379 for(int j=0;j<list.size();j+=2) {
380 Resource p = ss.getResource(list.getQuick(j));
381 Resource o = ss.getResource(list.getQuick(j+1));
382 result.add(new StandardStatement(subject, p, o));
387 } catch (DatabaseException e) {
393 void listValues(final SerialisationSupport ss, final ArrayList<Resource> result) {
395 values.forEachKey(new TIntProcedure() {
398 public boolean execute(int value) {
400 result.add(ss.getResource(getTransientId(value)));
401 } catch (DatabaseException e) {
413 public class TransientGraph implements VirtualGraphImpl, VirtualGraphContext {
414 private static final boolean DEBUG = VirtualCluster.DEBUG;
415 final private static int SWAP_LIMIT = 30;
417 // final private static byte[] NO_VALUE = new byte[0];
418 final private static VirtualCluster NO_CLUSTER = new VirtualCluster(-1);
420 final private Persistency persistency;
422 final private SerialisationSupport serialization;
423 final private ResourceSupport resourceSupport;
424 final private VirtualGraphServerSupport virtualGraphServerSupport;
425 final private AsyncRequestProcessor sessionRequestProcessor;
428 * Cluster array by index.
429 * -NO_CLUSTER value means that there is no such virtual cluster
430 * -null value means that such virtual cluster could be on disk
432 final private ArrayList<VirtualCluster> clusters = new ArrayList<VirtualCluster>();
435 * A list of resident clusters
437 final private LinkedList<VirtualCluster> memoryClusters = new LinkedList<VirtualCluster>();
439 private final HashSet<VirtualGraphSource> sources = new HashSet<VirtualGraphSource>();
441 final String identifier;
442 final String databaseId;
444 TIntObjectHashMap<TIntHashSet> NO_STATEMENTS = new TIntObjectHashMap<TIntHashSet>();
446 int[] EMPTY = new int[0];
448 public static TransientGraph workspacePersistent(SerialisationSupport ss, VirtualGraphServerSupport vgss, ResourceSupport rs, AsyncRequestProcessor srp, String databaseId, String identifier) throws DatabaseException {
449 TransientGraph graph = new TransientGraph(ss, vgss, rs, srp, databaseId, identifier, Persistency.WORKSPACE);
454 public static TransientGraph memoryPersistent(SerialisationSupport ss, VirtualGraphServerSupport vgss, ResourceSupport rs, AsyncRequestProcessor srp, String databaseId, String identifier) {
455 return new TransientGraph(ss, vgss, rs, srp, databaseId, identifier, Persistency.MEMORY);
458 private TransientGraph(SerialisationSupport ss, VirtualGraphServerSupport vgss, ResourceSupport rs, AsyncRequestProcessor srp, String databaseId, String identifier, Persistency persistency) {
459 this.serialization = ss;
460 this.virtualGraphServerSupport = vgss;
461 this.sessionRequestProcessor = srp;
462 this.resourceSupport = rs;
463 this.identifier = identifier;
464 this.databaseId = databaseId;
466 this.persistency = persistency;
469 public String getIdentifier() {
473 private int transientClusterId(long id) throws DatabaseException {
475 System.out.println("DEBUG: transientClusterId=" + id);
476 if ((id & 1) == 0) // Cluster of virtual subjects
478 // Corresponds to persistent cluster
479 int rk = serialization.getTransientId(id);
480 return ClusterTraitsBase.getClusterKeyFromResourceKey(rk) << 1 | 1;
483 private String getPrefix() {
484 return identifier + "." + persistency.identifier() + "." + databaseId;
487 private void load() throws DatabaseException {
489 String prefix = getPrefix();
490 for(String file : virtualGraphServerSupport.storagePath().list()) {
492 if(file.startsWith(prefix)) {
493 long clusterLong = Long.parseLong(file.substring(prefix.length()+4));
494 int clusterId = transientClusterId(clusterLong);
495 VirtualCluster cluster = new VirtualCluster(clusterId);
496 cluster.load(new File(virtualGraphServerSupport.storagePath(), file), serialization, (clusterId & 1) > 0 ? virtualGraphServerSupport : null);
497 clusters.ensureCapacity(clusterId+1);
498 for(int i=clusters.size(); i<clusterId+1; i++) clusters.add(null);
499 clusters.set(clusterId, cluster);
500 memoryClusters.addLast(cluster);
502 } catch (DatabaseException t) {
503 // file is assumably broken, delete it
504 File filee = new File(virtualGraphServerSupport.storagePath(), file);
505 if (!filee.delete()) {
506 System.err.println("Could not delete file " + filee.getAbsolutePath());
514 public void dispose() {
516 saveImpl(serialization);
517 } catch (IOException e) {
525 saveImpl(serialization);
526 } catch (IOException e) {
532 public void saveImpl(final SerialisationSupport ss) throws IOException {
534 for(VirtualCluster cluster : memoryClusters) {
535 String prefix = getPrefix();
536 File file = new File(virtualGraphServerSupport.storagePath(), prefix + ".vg." + VirtualCluster.getClusterIdentifier(ss, cluster.clusterId()));
537 cluster.saveImpl(file, ss);
543 * Closes a stream and ignores any resulting exception. This is useful
544 * when doing stream cleanup in a finally block where secondary exceptions
545 * are not worth logging.
547 static void uncheckedClose(Closeable closeable) {
549 if (closeable != null)
551 } catch (IOException e) {
556 private void trimClusters() {
557 for(VirtualCluster cluster : memoryClusters) {
563 * Returns a transient cluster index
564 * -Transient clusters for persistent resources have index with LSB=1
565 * -Transient clusters for virtual resources have index with LSB=0
567 * @param subject is a DB client transient id
569 * For persistent resources cluster id is 2*clusterKey+1
570 * For virtual resources transient ids are persistent and are directly chunked into 14-bit clusters.
573 public static int getVirtualClusterKey(int subject) {
575 int ck = ClusterTraitsBase.getClusterKeyFromResourceKeyNoThrow(subject);
576 return (ck << 1) | 1;
578 int ck = ClusterTraitsBase.getClusterKeyFromResourceKeyNoThrow(~subject);
582 private VirtualCluster getOrLoad(int virtualClusterKey) {
584 if(virtualClusterKey < clusters.size()) {
585 VirtualCluster cluster = clusters.get(virtualClusterKey);
586 if(NO_CLUSTER == cluster) return null;
587 if(cluster != null) return cluster;
590 System.out.println("Loading virtual cluster " + virtualClusterKey + " for " + identifier);
592 clusters.ensureCapacity(virtualClusterKey+1);
593 for(int i=clusters.size(); i<virtualClusterKey+1; i++) clusters.add(null);
595 //if(!VirtualCluster.isValidVirtualClusterKey(serialization, virtualClusterKey)) return null;
597 long clusterIdentifier = VirtualCluster.getClusterIdentifier(serialization, virtualClusterKey);
598 File file = new File(virtualGraphServerSupport.storagePath(), getPrefix() + ".vg." + clusterIdentifier);
600 VirtualCluster cluster = new VirtualCluster(virtualClusterKey);
601 // System.out.println("Loading virtual cluster2 " + virtualClusterKey + " for " + identifier);
603 cluster.load(file, serialization, (virtualClusterKey & 1) > 0 ? virtualGraphServerSupport : null);
604 clusters.set(virtualClusterKey, cluster);
605 memoryClusters.addFirst(cluster);
608 } catch (DatabaseException e) {
610 // File must be corrupt, lets delete it so we wont load it next time in future
613 clusters.set(virtualClusterKey, NO_CLUSTER);
618 clusters.set(virtualClusterKey, NO_CLUSTER);
623 private void swap() {
626 while(memoryClusters.size() > SWAP_LIMIT) {
627 VirtualCluster remo = memoryClusters.removeLast();
628 File file = new File(virtualGraphServerSupport.storagePath(), getPrefix() + ".vg." + VirtualCluster.getClusterIdentifier(serialization, remo.clusterId()));
630 remo.saveImpl(file, serialization);
631 } catch (IOException e) {
634 clusters.set(remo.clusterId(), null);
639 private synchronized VirtualCluster getCluster(int subject, boolean create) {
641 int clusterId = getVirtualClusterKey(subject);
643 VirtualCluster cluster = getOrLoad(clusterId);
644 if(cluster != null) return cluster;
648 clusters.ensureCapacity(clusterId+1);
649 for(int i=clusters.size(); i<clusterId+1; i++) clusters.add(null);
650 cluster = new VirtualCluster(clusterId);
651 clusters.set(clusterId, cluster);
652 memoryClusters.addFirst(cluster);
662 private synchronized void applyValue(int subject, Object value, Binding binding) {
665 Serializer serializer = Bindings.getSerializer( binding );
666 byte[] serialized = serializer.serialize(value);
667 VirtualCluster cluster = getCluster(subject, true);
668 cluster.setValue(subject, serialized, serialized.length);
669 } catch (SerializationException e) {
671 } catch (SerializerConstructionException e) {
673 } catch (IOException e) {
674 // TODO Auto-generated catch block
680 private synchronized void applyStatements(int subject, int[] statements) {
682 VirtualCluster cluster = getCluster(subject, true);
683 cluster.addStatements(subject, statements);
686 if(subject > 0) virtualGraphServerSupport.addVirtual(subject);
690 private synchronized void produceAllStatements(ReadGraphImpl graph, final int subject, final AsyncProcedure<Object> procedure) throws DatabaseException {
692 VirtualCluster cluster = getCluster(subject, true);
694 // This resource becomes a normal resource, all data is requeried
695 cluster.resetLazy(subject);
697 for(VirtualGraphSource source : sources) {
698 source.getStatements(graph, this, subject);
701 if(subject > 0) virtualGraphServerSupport.addVirtual(subject);
705 private synchronized void producePartialStatements(ReadGraphImpl graph, final int subject, final int predicate, final AsyncProcedure<Object> procedure) throws DatabaseException {
707 for(VirtualGraphSource source : sources) {
708 source.getStatements(graph, this, subject, predicate);
711 if(subject > 0) virtualGraphServerSupport.addVirtual(subject);
716 public int getIndex(Resource resource) {
718 return serialization.getTransientId(resource);
719 } catch (DatabaseException e) {
726 public Resource getResource(int index) {
727 return new ResourceImpl(resourceSupport, index);
731 public void register(final VirtualGraphSource source) {
732 if(sources.add(source)) {
733 source.attach(TransientGraph.this);
738 public void claim(int subject, int predicate, int object) {
740 VirtualCluster cluster = getCluster(subject, true);
741 cluster.claim(subject, predicate, object);
742 if(subject > 0) virtualGraphServerSupport.addVirtual(subject);
747 public synchronized int[] getObjects(int subject, int predicate) {
748 VirtualCluster cluster = getCluster(subject, false);
749 if(cluster == null) return EMPTY;
750 return cluster.getObjects(subject, predicate);
754 public synchronized int[] getPredicates(int subject) {
755 VirtualCluster cluster = getCluster(subject, false);
756 if(cluster == null) return EMPTY;
757 return cluster.getPredicates(subject);
761 public synchronized byte[] getValue(int subject) {
762 VirtualCluster cluster = getCluster(subject, false);
763 if(cluster == null) return null;
764 return cluster.getValue(subject);
768 public int newResource(boolean isLazy) {
770 int id = virtualGraphServerSupport.createVirtual();
771 VirtualCluster cluster = getCluster(id, true);
772 if(isLazy) cluster.setLazy(id);
778 public void finish(int subject) {
779 VirtualCluster cluster = getCluster(subject, false);
780 cluster.finish(subject);
784 public void deny(int subject, int predicate, int object) {
786 VirtualCluster cluster = getCluster(subject, true);
787 cluster.deny(subject, predicate, object);
792 public void claimValue(int subject, byte[] data, int length) {
794 VirtualCluster cluster = getCluster(subject, true);
795 cluster.setValue(subject, data, length);
796 if(subject > 0) virtualGraphServerSupport.addVirtual(subject);
801 public void denyValue(int subject) {
802 // FIXME: this implementation is probably not proper, Antti needs to work on this.
803 VirtualCluster cluster = getCluster(subject, true);
804 cluster.denyValue(subject);
805 if(subject > 0) virtualGraphServerSupport.removeVirtual(subject);
809 public void initialise(final Write write) {
811 sessionRequestProcessor.syncRequest(new WriteRequest(this) {
814 public void perform(WriteGraph graph) throws DatabaseException {
815 write.perform(graph);
819 } catch (DatabaseException e) {
825 public void postModification(AsyncRequestProcessor processor, final WriteOnly request) {
827 if(processor == null) processor = sessionRequestProcessor;
829 processor.asyncRequest(new WriteOnlyRequest(this) {
832 public void perform(WriteOnlyGraph graph) throws DatabaseException {
833 request.perform(graph);
841 public void updateStatements(int resource, int[] statements) {
842 applyStatements(resource, statements);
846 public void updateValue(int resource, Object value, Binding binding) {
847 applyValue(resource, value, binding);
851 public boolean isPending(int subject) {
853 VirtualCluster cluster = getCluster(subject, false);
854 if(cluster == null) return false;
855 else return cluster.isPending(subject);
860 public boolean isPending(int subject, int predicate) {
862 VirtualCluster cluster = getCluster(subject, false);
863 if(cluster == null) return false;
864 else return cluster.isPending(subject, predicate);
869 public void load(ReadGraphImpl graph, int resource, int predicate, final Consumer<ReadGraphImpl> callback) throws DatabaseException {
870 producePartialStatements(graph, resource, predicate, new AsyncProcedure<Object>() {
873 public void execute(AsyncReadGraph graph, Object result) {
874 callback.accept((ReadGraphImpl)graph);
878 public void exception(AsyncReadGraph graph, Throwable throwable) {
879 callback.accept((ReadGraphImpl)graph);
886 public void load(ReadGraphImpl graph, int resource, final Consumer<ReadGraphImpl> callback) throws DatabaseException {
887 produceAllStatements(graph, resource, new AsyncProcedure<Object>() {
890 public void execute(AsyncReadGraph graph, Object result) {
891 callback.accept((ReadGraphImpl)graph);
895 public void exception(AsyncReadGraph graph, Throwable throwable) {
896 callback.accept((ReadGraphImpl)graph);
902 public Collection<Statement> listStatements() {
903 ArrayList<Statement> result = new ArrayList<Statement>();
904 for(int i=0;i<clusters.size();i++) {
905 VirtualCluster cluster = getOrLoad(i);
906 if(cluster != null) {
907 cluster.listStatements(serialization, result);
913 public Collection<Resource> listValues() {
914 ArrayList<Resource> result = new ArrayList<Resource>();
915 for(int i=0;i<clusters.size();i++) {
916 VirtualCluster cluster = getOrLoad(i);
917 if(cluster != null) {
918 cluster.listValues(serialization, result);
925 public Persistency getPersistency() {
930 public String toString() {
931 String result = "'" + identifier + "'";
932 if(Persistency.WORKSPACE == persistency) result += " (W)";
933 else if(Persistency.MEMORY == persistency) result += " (M)";