package org.simantics.acorn.lru; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.file.Path; import org.simantics.acorn.ClusterManager; import org.simantics.acorn.Persistable; import org.simantics.acorn.cluster.ClusterImpl; import org.simantics.acorn.cluster.ClusterSmall; import org.simantics.acorn.exception.AcornAccessVerificationException; import org.simantics.acorn.exception.IllegalAcornStateException; import org.simantics.acorn.cluster.ClusterImpl.ClusterTables; import org.simantics.acorn.internal.ClusterSupport2; import org.simantics.compressions.CompressionCodec; import org.simantics.compressions.Compressions; import org.simantics.db.ClusterCreator; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.SDBException; import org.simantics.db.service.Bytes; import org.simantics.db.service.ClusterUID; import org.simantics.utils.datastructures.Pair; public class ClusterInfo extends LRUObject implements Persistable { final private ClusterManager manager; private ClusterImpl cluster; public int changeSetId; private ClusterUpdateState updateState; public static final String COMPRESSION = "LZ4"; // Stub public ClusterInfo(ClusterManager manager, LRU LRU, Path readDirectory, ClusterUID uid, int offset, int length) throws AcornAccessVerificationException { super(LRU, uid, readDirectory, uid.toString() + ".cluster", offset, length, false, false); this.manager = manager; this.cluster = null; LRU.map(this); } // New public ClusterInfo(ClusterManager manager, LRU LRU, ClusterImpl cluster) throws AcornAccessVerificationException, IllegalAcornStateException { super(LRU, cluster.getClusterUID(), LRU.getDirectory(), cluster.getClusterUID().toString() + ".cluster", true, true); this.manager = manager; this.cluster = cluster; LRU.insert(this, accessTime); LRU.swap(getKey()); } public T clone(ClusterUID uid, ClusterCreator creator) throws IOException, AcornAccessVerificationException, IllegalAcornStateException { // Updates have been ensured at this point acquireMutex(); try { if(isResident()) { ClusterTables tables = cluster.store(); return creator.create(uid, tables.bytes, tables.ints, tables.longs); } } catch (IOException e) { throw e; } catch (Throwable t) { throw new IllegalAcornStateException(t); } finally { releaseMutex(); } // Ensure pending updates here - this may take some time LRU.waitPending(this, false); acquireMutex(); try { if(isResident()) { ClusterTables tables = cluster.store(); return creator.create(uid, tables.bytes, tables.ints, tables.longs); } else { byte[] data = readFile(); ClusterTables tables = new ClusterTables(); loadCluster(getKey(), manager.support, data, tables); return creator.create(uid, tables.bytes, tables.ints, tables.longs); } } catch (IOException e) { throw e; } catch (Throwable t) { throw new IllegalAcornStateException(t); } finally { releaseMutex(); } } static class ClusterDecompressor { byte[] decompressBuffer = new byte[1024*1024]; public synchronized ClusterTables readCluster(ClusterUID uid, byte[] compressed) throws IOException { int deflatedSize = Bytes.readLE4(compressed, compressed.length-4); if(decompressBuffer.length < deflatedSize) decompressBuffer = new byte[Math.max(3*decompressBuffer.length / 2, deflatedSize)]; CompressionCodec codec = Compressions.get(Compressions.LZ4); ByteBuffer input = ByteBuffer.wrap(compressed); ByteBuffer output = ByteBuffer.wrap(decompressBuffer); int decompressedSize = codec.decompressBuffer(input, 0, compressed.length-4, output, 0, decompressBuffer.length); assert(decompressedSize <= decompressBuffer.length); int byteLength = Bytes.readLE4(decompressBuffer, 0); int intLength = Bytes.readLE4(decompressBuffer, 4); int longLength = Bytes.readLE4(decompressBuffer, 8); byte[] bytes = new byte[byteLength]; int[] ints = new int[intLength]; long[] longs = new long[longLength]; System.arraycopy(decompressBuffer, 12, bytes, 0, byteLength); int offset = 12+byteLength; for(int i=0;i toBytes() throws IllegalAcornStateException { try { byte[] raw = null; if(cluster instanceof ClusterSmall) { raw = cluster.storeBytes(); } else { ClusterTables tables = cluster.store(); raw = new byte[12 + tables.bytes.length + (tables.ints.length<<2) + (tables.longs.length<<3)]; Bytes.writeLE(raw, 0, tables.bytes.length); Bytes.writeLE(raw, 4, tables.ints.length); Bytes.writeLE(raw, 8, tables.longs.length); System.arraycopy(tables.bytes, 0, raw, 12, tables.bytes.length); int offset = 12+tables.bytes.length; for(int i=0;i