Author: bpoussin Date: 2012-09-07 19:35:57 +0200 (Fri, 07 Sep 2012) New Revision: 3767 Url: http://forge.codelutin.com/repositories/revision/isis-fish/3767 Log: - Correction dans le stockage des resultats en fichier mapper - ajout d'un marqueur en debut de resultat pour de futur evolution - outil de reparation - ajout d'autre type de resultat Added: trunk/src/main/java/fr/ifremer/isisfish/util/BitUtil.java trunk/src/test/java/fr/ifremer/isisfish/util/BitUtilTest.java Modified: trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultMappedStorage.java trunk/src/test/java/fr/ifremer/isisfish/AbstractIsisFishTest.java Modified: trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultMappedStorage.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultMappedStorage.java 2012-09-06 13:39:35 UTC (rev 3766) +++ trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultMappedStorage.java 2012-09-07 17:35:57 UTC (rev 3767) @@ -41,6 +41,7 @@ import fr.ifremer.isisfish.simulator.SimulationResultListener; import fr.ifremer.isisfish.types.Month; import fr.ifremer.isisfish.types.TimeStep; +import fr.ifremer.isisfish.util.BitUtil; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; @@ -191,46 +192,135 @@ protected String name; protected MatrixND matrix; - /** read data from file */ - public ResultMapped(RandomAccessFile raf, long offset) throws IOException { - this.raf = raf; - this.offset = offset; + /** + * Classe permettant de lire et ecrire le header d'un resultat matrice + * Le header comprend tout sauf les donnees de la matrice. + * Si on ne retrouve pas la mark, alors on ne lit pas le resultat. + * Cette classe sert a simplifier la lecture et l'ecriture pour garantir + * la symetrie entre les deux + */ + static protected class ResultHeaderMatrix { + final static long RESULT_MATRIX = BitUtil.toMark("res mat"); - int stepValue = raf.readInt(); - step = new TimeStep(stepValue); + int stepValue; // le pas de temps + String name; // le nom du resultat + int dimSize; // le nombre de dimension + String[] dimNames; // le nom des dimensions + int[] dims; // la taille de chaque dimension + List[] sems; // les semantiques de chaque dimension + int dataSize; // la taille du vecteur. En mettant un int on est limite a 2Go x 8 (double) = 16Go par matrice - name = raf.readUTF(); + /** + * Methode qui prend tous les champs en parametre, ce qui force a ne pas en oublier + * @param stepValue + * @param name + * @param dimSize + * @param dimNames + * @param dims + * @param sems + * @param dataSize + */ + public void set(int stepValue, String name, int dimSize, + String[] dimNames, int[] dims, List[] sems, int dataSize) { + this.stepValue = stepValue; + this.name = name; + this.dimSize = dimSize; + this.dimNames = dimNames; + this.dims = dims; + this.sems = sems; + this.dataSize = dataSize; + } - int dimSize = raf.readInt(); + /** + * Lit le header si possible. Si ce n'est pas possible replace le + * raf a l'emplacement auquel il etait avant la tentative de lecture. + * + * @param raf + * @return + * @throws IOException + */ + public static ResultHeaderMatrix read (RandomAccessFile raf) throws IOException { + long pos = raf.getFilePointer(); - String[] dimNames = new String[dimSize]; - for (int i=0; i<dimSize; i++) { - dimNames[i] = raf.readUTF(); - } + long mark = raf.readLong(); + ResultHeaderMatrix result = null; + if (mark != RESULT_MATRIX) { + // on a pas le bon marqueur, on se replace avant sa lecture + raf.seek(pos); + } else { + result = new ResultHeaderMatrix(); + result.stepValue = raf.readInt(); + result.name = raf.readUTF(); + result.dimSize = raf.readInt(); + result.dimNames = new String[result.dimSize]; + for (int i=0; i< result.dimSize; i++) { + result.dimNames[i] = raf.readUTF(); + } + result.dims = new int[result.dimSize]; + for (int i=0; i< result.dimSize; i++) { + result.dims[i] = raf.readInt(); + } - int[] dims = new int[dimSize]; - for (int i=0; i<dimSize; i++) { - dims[i] = raf.readInt(); + result.sems = new List[result.dimSize]; + for (int i=0; i< result.dimSize; i++) { + result.sems[i] = new ArrayList(); + for (int j=0; j< result.dims[i]; j++) { + String s = raf.readUTF(); + result.sems[i].add(s); + } + } + result.dataSize = raf.readInt(); + } + return result; } + public void write (RandomAccessFile raf) throws IOException { + long mark = RESULT_MATRIX; - List[] sems = new List[dimSize]; - for (int i=0; i<dimSize; i++) { - sems[i] = new ArrayList(); - for (int j=0; j<dims[i]; j++) { - String s = raf.readUTF(); - sems[i].add(s); + raf.writeLong(mark); + raf.writeInt(this.stepValue); + raf.writeUTF(this.name); + raf.writeInt(this.dimSize); + for (int i=0; i< this.dimSize; i++) { + raf.writeUTF(this.dimNames[i]); } + for (int i=0; i< this.dimSize; i++) { + raf.writeInt(this.dims[i]); + } + + + for (int i=0; i< this.sems.length; i++) { + for (Object s : this.sems[i]) { + raf.writeUTF(String.valueOf(s)); + } + } + raf.writeInt(this.dataSize); } + } - long size = raf.getFilePointer(); - long dataOffset = offset + size; - int dataSize = raf.readInt(); // en mettant un int on est limite a 2Go x 8 (double) = 16Go par matrice - DoubleBigMappedVector data = new DoubleBigMappedVector(raf, dataOffset, dataSize); - this.matrix = matrixFactory.create(name, sems, dimNames, data); - size += dataSize * 8; /* un double est sur 8 bytes*/ - this.size = size; + /** read data from file */ + public ResultMapped(RandomAccessFile raf, long offset) throws IOException { + this.raf = raf; + this.offset = offset; + ResultHeaderMatrix header = ResultHeaderMatrix.read(raf); + if (header != null) { + step = new TimeStep(header.stepValue); + name = header.name; + String[] dimNames = header.dimNames; + List[] sems = header.sems; + + long size = raf.getFilePointer(); + long dataOffset = offset + size; + + int dataSize = header.dataSize; + + DoubleBigMappedVector data = new DoubleBigMappedVector(raf, dataOffset, dataSize); + this.matrix = matrixFactory.create(name, sems, dimNames, data); + + size += dataSize * 8; /* un double est sur 8 bytes*/ + this.size = size; + } } /** write date to file */ @@ -246,18 +336,7 @@ List[] sems = matrix.getSemantics(); int dataSize = MatrixHelper.getVectorSize(dims); // en mettant un int on est limite a 2Go x 8 (double) = 16Go par matrice - raf.write(step.getStep()); // ecriture du pas de temps - raf.writeUTF(name); // ecriture du nom du resultat - raf.write(dims.length); // ecriture de la taille du tableau de dimension et semantique - - for (String s : dimNames) { - raf.writeUTF(s); // ecriture du nom de chaque dimensions - } - for (int d : dims) { - raf.write(d); // ecriture de chaque dimension - } - - // conversion et enregistrement des semantiques + // conversion des semantiques SemanticsDecorator deco = new EntitySemanticsDecorator(); for (int i=0; i<sems.length; i ++) { List l = sems[i]; @@ -266,11 +345,12 @@ for (Object o : l) { o = deco.undecorate(o); undecorate.add(o); - raf.writeUTF(o.toString()); // ecriture de chaque dimension } } - raf.writeInt(dataSize); + ResultHeaderMatrix header = new ResultHeaderMatrix(); + header.set(step.getStep(), name, dims.length, dimNames, dims, sems, dataSize); + header.write(raf); // on prend la position apres l'ecriture de l'entete long size = raf.getFilePointer(); @@ -452,6 +532,7 @@ ResultMapped r = new ResultMapped(raf, offset, step, name, mat); storeResult(r); offset += r.size(); + raf.getFD().sync(); } catch (IOException eee) { log.warn("Can't add result '" + name + "' at step " + step, eee); } @@ -480,7 +561,7 @@ */ public boolean isEnabled(String name) { name = name.trim(); - if (enabledResult == null) { + if (enabledResult == null && simulation.getSimulationParametersFile().exists()) { enabledResult = new HashSet<String>(); Collection<String> resultEnabled = simulation.getParameter() @@ -538,7 +619,11 @@ } log.info("Enabled result: " + enabledResult); } - boolean result = enabledResult.contains(name); + // par defaut on dit qu'on conserve le resultat + boolean result = true; + if (enabledResult != null) { + result = enabledResult.contains(name); + } return result; } Added: trunk/src/main/java/fr/ifremer/isisfish/util/BitUtil.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/util/BitUtil.java (rev 0) +++ trunk/src/main/java/fr/ifremer/isisfish/util/BitUtil.java 2012-09-07 17:35:57 UTC (rev 3767) @@ -0,0 +1,77 @@ +package fr.ifremer.isisfish.util; + + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Quelques methodes pour manipuler les bits d'un long. Ces methodes servent pour + * creer des marques pour les resultats mapper + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +public class BitUtil { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(BitUtil.class); + /** + * Converti une chaine de maximum 8 carateres en un long representant cette + * chaine en ascii. + * @param s + * @return + */ + public static long toMark(String s) { + long result = 0; + s = StringUtils.rightPad(s, 8, ' '); + s = StringUtils.substring(s, 0, 8); + for (int i=0; i<8; i++) { + long b = (long)s.charAt(i); + // le 1er caractere doit etre le plus a gauche + // un long est sur 64 bit, on decale de 8 en 8 (byte) + result = result | (b << (64-(i+1)*8)); + } + return result; + } + + /** + * Convertie un long en sa representation String. Le long est en fait + * l'aggregation de 8 char (8x8bits). Les chars sont dans la table ascii + * @param l + * @return + */ + public static String fromMark(long l) { + long m = 0x00000000000000FF; // mask 255 + String result = ""; + for (int i=0; i<8; i++) { // on parcours chaque byte du long + long t = l >> 8*i; // on decale le caratere a lire a droite + char v = (char)(t & m); // on applique le mask pour ne garder que ce caratere + result = v + result; + } + return result; + } + + /** + * Montre les bits d'une nombre entier + * @param l + * @return + */ + public static String showBit(long l) { + long m = 0x0000000000000001; + String result = ""; + for (int i=0; i<64; i++) { + long t = l >> i; + long v = t & m; + result = v + result; + if (i!= 0 && i%8 == 0) { + result = " " + result; + } + } + return result; + } + +} Modified: trunk/src/test/java/fr/ifremer/isisfish/AbstractIsisFishTest.java =================================================================== --- trunk/src/test/java/fr/ifremer/isisfish/AbstractIsisFishTest.java 2012-09-06 13:39:35 UTC (rev 3766) +++ trunk/src/test/java/fr/ifremer/isisfish/AbstractIsisFishTest.java 2012-09-07 17:35:57 UTC (rev 3767) @@ -40,6 +40,7 @@ import freemarker.cache.ClassTemplateLoader; import freemarker.ext.beans.BeansWrapper; import freemarker.template.Configuration; +import java.io.IOException; /** * Abstract test case for isis fish. Added: trunk/src/test/java/fr/ifremer/isisfish/util/BitUtilTest.java =================================================================== --- trunk/src/test/java/fr/ifremer/isisfish/util/BitUtilTest.java (rev 0) +++ trunk/src/test/java/fr/ifremer/isisfish/util/BitUtilTest.java 2012-09-07 17:35:57 UTC (rev 3767) @@ -0,0 +1,34 @@ +package fr.ifremer.isisfish.util; + + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Test; + +/** + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +public class BitUtilTest { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(BitUtilTest.class); + /** + * Test que la conversion chaine vers long fonctionne pour la creation de mark + */ + @Test + public void testMark() { + String s = "res mat"; + long l = BitUtil.toMark(s); + String r = BitUtil.fromMark(l); + + // le resultat fait toujours 8 caracteres, s'il faut des espaces son ajouter + Assert.assertEquals(s + " ", r); + } + +}