Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
03/11/10 15:50:50 (15 years ago)
Author:
epitzer
Message:

add support for type information interleaving and subsequently true streaming (#548)

Location:
trunk/sources/HeuristicLab.Persistence/3.3
Files:
1 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Persistence/3.3/Core/DeSerializer.cs

    r3004 r3005  
    7777      parentStack = new Stack<Midwife>();
    7878      typeIds = new Dictionary<int, Type>();
    79       serializerMapping = CreateSerializers(typeCache);
    80     }
    81 
    82     private Dictionary<Type, object> CreateSerializers(IEnumerable<TypeMapping> typeCache) {
    83       Dictionary<Type, object> serializerInstances = new Dictionary<Type, object>();
     79      serializerMapping = new Dictionary<Type, object>();
     80      foreach (var typeMapping in typeCache) {
     81        AddTypeInfo(typeMapping);
     82      }
     83    }
     84
     85    private Dictionary<Type, object> serializerInstances = new Dictionary<Type, object>();   
     86
     87    public void AddTypeInfo(TypeMapping typeMapping) {
     88      if (typeIds.ContainsKey(typeMapping.Id))
     89        return;
    8490      try {
    85         var map = new Dictionary<Type, object>();
    86         foreach (var typeMapping in typeCache) {
    87           Type type = TypeLoader.Load(typeMapping.TypeName);
    88           typeIds.Add(typeMapping.Id, type);
    89           Type serializerType = TypeLoader.Load(typeMapping.Serializer);
    90           object serializer;
    91           if (serializerInstances.ContainsKey(serializerType))
    92             serializer = serializerInstances[serializerType];
    93           else
    94             serializer = Activator.CreateInstance(serializerType, true);
    95           map.Add(type, serializer);
    96         }
    97         return map;
     91        Type type = TypeLoader.Load(typeMapping.TypeName);
     92        typeIds.Add(typeMapping.Id, type);
     93        Type serializerType = TypeLoader.Load(typeMapping.Serializer);
     94        object serializer;
     95        if (serializerInstances.ContainsKey(serializerType))
     96          serializer = serializerInstances[serializerType];
     97        else
     98          serializer = Activator.CreateInstance(serializerType, true);
     99        serializerMapping.Add(type, serializer);
    98100      } catch (PersistenceException) {
    99101        throw;
    100102      } catch (Exception e) {
    101         throw new PersistenceException(
    102           "The serialization type cache could not be loaded.\r\n" +
    103           "This usualy happens when you are missing an Assembly or Plugin.", e);
     103        throw new PersistenceException(string.Format(
     104          "Could not add type info for {0} ({1})",
     105          typeMapping.TypeName, typeMapping.Serializer), e);
    104106      }
    105107    }
     
    125127        } else if (t == typeof(MetaInfoEndToken)) {
    126128          MetaInfoEnd((MetaInfoEndToken)token);
     129        } else if (t == typeof(TypeToken)) {
     130          Type((TypeToken)token);
    127131        } else {
    128132          throw new PersistenceException("invalid token type");
     
    138142      if (!m.MetaMode && m.Obj == null)
    139143        CreateInstance(m);
     144    }
     145
     146    private void Type(TypeToken token) {
     147      AddTypeInfo(new TypeMapping(token.Id, token.TypeName, token.Serializer));
    140148    }
    141149
  • trunk/sources/HeuristicLab.Persistence/3.3/Core/GeneratorBase.cs

    r3004 r3005  
    3434      if (type == typeof(MetaInfoEndToken))
    3535        return Format((MetaInfoEndToken)token);
     36      if (type == typeof(TypeToken))
     37        return Format((TypeToken)token);
    3638      throw new ApplicationException("Invalid token of type " + type.FullName);
    3739    }
     
    4446    protected abstract T Format(MetaInfoBeginToken metaInfoBeginToken);
    4547    protected abstract T Format(MetaInfoEndToken metaInfoEndToken);
     48    protected abstract T Format(TypeToken typeToken);
    4649
    4750  }
  • trunk/sources/HeuristicLab.Persistence/3.3/Core/Serializer.cs

    r3004 r3005  
    4949    private readonly bool isTestRun;
    5050    private readonly List<Exception> exceptions;
     51
     52    public bool InterleaveTypeInformation { get; set; }
    5153
    5254    /// <summary>
     
    106108    /// don't stop at the first exception</param>
    107109    public Serializer(object obj, Configuration configuration, string rootName, bool isTestRun) {
     110      this.InterleaveTypeInformation = false;
    108111      this.obj = obj;
    109112      this.rootName = rootName;
     
    144147      if (obj2id.ContainsKey(value))
    145148        return ReferenceEnumerator(accessor.Name, obj2id[value]);
    146       if (!typeCache.ContainsKey(type))
     149      bool emitTypeInfo = false;
     150      if (!typeCache.ContainsKey(type)) {
    147151        typeCache.Add(type, typeCache.Count);
     152        emitTypeInfo = InterleaveTypeInformation;
     153      }
    148154      int typeId = typeCache[type];
    149155      int? id = null;
     
    155161        IPrimitiveSerializer primitiveSerializer = configuration.GetPrimitiveSerializer(type);
    156162        if (primitiveSerializer != null)
    157           return PrimitiveEnumerator(accessor.Name, typeId, primitiveSerializer.Format(value), id);
     163          return PrimitiveEnumerator(
     164            accessor.Name,
     165            typeId,
     166            primitiveSerializer.Format(value),
     167            id,
     168            emitTypeInfo);
    158169        ICompositeSerializer compositeSerializer = configuration.GetCompositeSerializer(type);
    159170        if (compositeSerializer != null)
    160           return CompositeEnumerator(accessor.Name, compositeSerializer.Decompose(value), id, typeId, compositeSerializer.CreateMetaInfo(value));
     171          return CompositeEnumerator(
     172            accessor.Name,
     173            compositeSerializer.Decompose(value),
     174            id,
     175            typeId,
     176            compositeSerializer.CreateMetaInfo(value),
     177            emitTypeInfo);
    161178        throw CreatePersistenceException(type);
    162179      } catch (Exception x) {
     
    200217
    201218    private IEnumerator<ISerializationToken> PrimitiveEnumerator(string name,
    202         int typeId, ISerialData serializedValue, int? id) {
     219        int typeId, ISerialData serializedValue, int? id, bool emitTypeInfo) {
     220      if (emitTypeInfo) {
     221        var mapping = TypeCache[typeId];
     222        yield return new TypeToken(mapping.Id, mapping.TypeName, mapping.Serializer);
     223      }
    203224      yield return new PrimitiveToken(name, typeId, id, serializedValue);
    204225    }
    205226
    206227    private IEnumerator<ISerializationToken> CompositeEnumerator(
    207         string name, IEnumerable<Tag> tags, int? id, int typeId, IEnumerable<Tag> metaInfo) {
     228        string name, IEnumerable<Tag> tags, int? id, int typeId, IEnumerable<Tag> metaInfo,
     229        bool emitTypeInfo) {
     230      if (emitTypeInfo) {
     231        var mapping = TypeCache[typeId];
     232        yield return new TypeToken(mapping.Id, mapping.TypeName, mapping.Serializer);
     233      }
    208234      yield return new BeginToken(name, typeId, id);
    209235      bool first = true;
  • trunk/sources/HeuristicLab.Persistence/3.3/Default/DebugString/DebugStringGenerator.cs

    r1612 r3005  
    9797    }
    9898
     99    protected override string Format(TypeToken typeToken) {
     100      return string.Empty;
     101    }
     102
    99103    public static string Serialize(object o) {
    100104      return Serialize(o, ConfigurationService.Instance.GetDefaultConfig(new DebugStringFormat()));
  • trunk/sources/HeuristicLab.Persistence/3.3/Default/Xml/XmlGenerator.cs

    r3004 r3005  
    88using HeuristicLab.Tracing;
    99using HeuristicLab.Persistence.Core.Tokens;
     10using System.IO.Compression;
    1011
    1112namespace HeuristicLab.Persistence.Default.Xml {
     
    109110
    110111    protected override string Format(BeginToken beginToken) {
    111       return CreateNodeStart(
    112         XmlStringConstants.COMPOSITE,
    113         new Dictionary<string, object> {
     112      var dict = new Dictionary<string, object> {
    114113          {"name", beginToken.Name},
    115114          {"typeId", beginToken.TypeId},
    116           {"id", beginToken.Id}});
     115          {"id", beginToken.Id}};
     116      AddTypeInfo(beginToken.TypeId, dict);
     117      return CreateNodeStart(XmlStringConstants.COMPOSITE, dict);
     118       
     119    }
     120
     121    private void AddTypeInfo(int typeId, Dictionary<string, object> dict) {
     122      if (lastTypeToken != null) {
     123        if (typeId == lastTypeToken.Id) {
     124          dict.Add("typeName", lastTypeToken.TypeName);
     125          dict.Add("serializer", lastTypeToken.Serializer);
     126          lastTypeToken = null;
     127        } else {
     128          FlushTypeToken();
     129        }
     130      }
    117131    }
    118132
     
    122136
    123137    protected override string Format(PrimitiveToken dataToken) {
    124       return CreateNode(XmlStringConstants.PRIMITIVE,
    125         new Dictionary<string, object> {
     138      var dict = new Dictionary<string, object> {
    126139            {"typeId", dataToken.TypeId},
    127140            {"name", dataToken.Name},
    128             {"id", dataToken.Id}},
     141            {"id", dataToken.Id}};
     142      AddTypeInfo(dataToken.TypeId, dict);
     143      return CreateNode(XmlStringConstants.PRIMITIVE, dict,
    129144        ((XmlString)dataToken.SerialData).Data);
    130145    }
     
    149164    protected override string Format(MetaInfoEndToken metaInfoEndToken) {
    150165      return CreateNodeEnd(XmlStringConstants.METAINFO);
     166    }
     167
     168    private TypeToken lastTypeToken;
     169    protected override string Format(TypeToken token) {
     170      lastTypeToken = token;
     171      return "";
     172    }
     173
     174    private string FlushTypeToken() {
     175      if (lastTypeToken == null)
     176        return "";
     177      try {
     178        return CreateNode(XmlStringConstants.TYPE,
     179          new Dictionary<string, object> {
     180          {"id", lastTypeToken.Id},
     181          {"typeName", lastTypeToken.TypeName },
     182          {"serializer", lastTypeToken.Serializer }});
     183      } finally {
     184        lastTypeToken = null;
     185      }
    151186    }
    152187
     
    182217    }
    183218
    184 
    185219    public static void Serialize(object obj, string filename, Configuration config) {
    186220      Serialize(obj, filename, config, false, 5);
     
    192226        DateTime start = DateTime.Now;
    193227        using (FileStream stream = File.Create(tempfile)) {
    194           Serialize(obj, stream, config, includeAssemblies, compression);
     228          Serializer serializer = new Serializer(obj, config);
     229          serializer.InterleaveTypeInformation = false;
     230          XmlGenerator generator = new XmlGenerator();
     231          using (ZipOutputStream zipStream = new ZipOutputStream(stream)) {
     232            zipStream.IsStreamOwner = false;
     233            zipStream.SetLevel(compression);
     234            zipStream.PutNextEntry(new ZipEntry("data.xml") { DateTime = DateTime.MinValue });
     235            StreamWriter writer = new StreamWriter(zipStream);
     236            foreach (ISerializationToken token in serializer) {
     237              string line = generator.Format(token);
     238              writer.Write(line);
     239            }
     240            writer.Flush();
     241            zipStream.PutNextEntry(new ZipEntry("typecache.xml") { DateTime = DateTime.MinValue });
     242            foreach (string line in generator.Format(serializer.TypeCache)) {
     243              writer.Write(line);
     244            }
     245            writer.Flush();
     246            if (includeAssemblies) {
     247              foreach (string name in serializer.RequiredFiles) {
     248                Uri uri = new Uri(name);
     249                if (!uri.IsFile) {
     250                  Logger.Warn("cannot read non-local files");
     251                  continue;
     252                }
     253                zipStream.PutNextEntry(new ZipEntry(Path.GetFileName(uri.PathAndQuery)));
     254                FileStream reader = File.OpenRead(uri.PathAndQuery);
     255                byte[] buffer = new byte[1024 * 1024];
     256                while (true) {
     257                  int bytesRead = reader.Read(buffer, 0, 1024 * 1024);
     258                  if (bytesRead == 0)
     259                    break;
     260                  zipStream.Write(buffer, 0, bytesRead);
     261                }
     262                writer.Flush();
     263              }
     264            }
     265          }
    195266        }
    196267        Logger.Info(String.Format("serialization took {0} seconds with compression level {1}",
     
    204275    }
    205276
     277    public static void Serialize(object obj, Stream stream) {
     278      Serialize(obj, stream, ConfigurationService.Instance.GetConfiguration(new XmlFormat()));
     279    }
     280
    206281
    207282    public static void Serialize(object obj, Stream stream, Configuration config) {
    208283      Serialize(obj, stream, config, false);
    209284    }
    210    
     285
    211286    public static void Serialize(object obj, Stream stream, Configuration config, bool includeAssemblies) {
    212       Serialize(obj, stream, config, includeAssemblies, 9);
    213     }
    214 
    215     public static void Serialize(object obj, Stream stream, Configuration config, bool includeAssemblies, int compression) {     
     287      Serialize(obj, stream, config, includeAssemblies, true);
     288    }
     289
     290    public static void Serialize(object obj, Stream stream, Configuration config, bool includeAssemblies, bool interleaveTypeInfo) {     
    216291      try {
    217         Serializer serializer = new Serializer(obj, config);
    218         XmlGenerator generator = new XmlGenerator();
    219         using (ZipOutputStream zipStream = new ZipOutputStream(stream)) {
    220           zipStream.IsStreamOwner = false;
    221           zipStream.SetLevel(compression);
    222           zipStream.PutNextEntry(new ZipEntry("data.xml") { DateTime = DateTime.MinValue });
    223           StreamWriter writer = new StreamWriter(zipStream);
     292        using (StreamWriter writer = new StreamWriter(new GZipStream(stream, CompressionMode.Compress))) {
     293          Serializer serializer = new Serializer(obj, config);
     294          serializer.InterleaveTypeInformation = true;
     295          XmlGenerator generator = new XmlGenerator();
    224296          foreach (ISerializationToken token in serializer) {
    225297            string line = generator.Format(token);
     
    227299          }
    228300          writer.Flush();
    229           zipStream.PutNextEntry(new ZipEntry("typecache.xml") { DateTime = DateTime.MinValue });
    230           foreach (string line in generator.Format(serializer.TypeCache)) {
    231             writer.Write(line);
    232           }
    233           writer.Flush();
    234           if (includeAssemblies) {
    235             foreach (string name in serializer.RequiredFiles) {
    236               Uri uri = new Uri(name);
    237               if (!uri.IsFile) {
    238                 Logger.Warn("cannot read non-local files");
    239                 continue;
    240               }
    241               zipStream.PutNextEntry(new ZipEntry(Path.GetFileName(uri.PathAndQuery)));
    242               FileStream reader = File.OpenRead(uri.PathAndQuery);
    243               byte[] buffer = new byte[1024 * 1024];
    244               while (true) {
    245                 int bytesRead = reader.Read(buffer, 0, 1024 * 1024);
    246                 if (bytesRead == 0)
    247                   break;
    248                 zipStream.Write(buffer, 0, bytesRead);
    249               }
    250               writer.Flush();
    251             }
    252           }
    253301        }
    254302      } catch (PersistenceException) {
     
    256304      } catch (Exception e) {
    257305        throw new PersistenceException("Unexpected exception during Serialization.", e);
    258       }     
     306      }
    259307    }
    260308  }
  • trunk/sources/HeuristicLab.Persistence/3.3/Default/Xml/XmlParser.cs

    r2874 r3005  
    88using ICSharpCode.SharpZipLib.Zip;
    99using HeuristicLab.Persistence.Core.Tokens;
     10using System.IO.Compression;
    1011
    1112namespace HeuristicLab.Persistence.Default.Xml {
     
    3031                     {XmlStringConstants.NULL, ParseNull},
    3132                     {XmlStringConstants.METAINFO, ParseMetaInfo},
     33                     {XmlStringConstants.TYPE, ParseTypeInfo},
    3234                   };
    3335    }
     
    5961      string name = reader.GetAttribute("name");
    6062      int typeId = int.Parse(reader.GetAttribute("typeId"));
     63      string typeName = reader.GetAttribute("typeName");
     64      string serializer = reader.GetAttribute("serializer");
     65      if (typeName != null)
     66        yield return new TypeToken(typeId, typeName, serializer);
    6167      XmlReader inner = reader.ReadSubtree();
    6268      inner.Read();
     
    7379        id = int.Parse(idString);
    7480      int typeId = int.Parse(reader.GetAttribute("typeId"));
     81      string typeName = reader.GetAttribute("typeName");
     82      string serializer = reader.GetAttribute("serializer");
     83      if (typeName != null)
     84        yield return new TypeToken(typeId, typeName, serializer);
    7585      yield return new BeginToken(name, typeId, id);
    7686      IEnumerator<ISerializationToken> iterator = GetEnumerator();
     
    96106        yield return iterator.Current;
    97107      yield return new MetaInfoEndToken();
     108    }
     109
     110    private IEnumerator<ISerializationToken> ParseTypeInfo() {
     111      yield return new TypeToken(
     112        int.Parse(reader.GetAttribute("id")),
     113        reader.GetAttribute("typeName"),
     114        reader.GetAttribute("serializer"));
    98115    }
    99116
     
    129146
    130147    public static object Deserialize(Stream stream) {
    131       using (ZipFile file = new ZipFile(stream)) {
    132         return Deserialize(file);
     148      try {
     149        using (StreamReader reader = new StreamReader(new GZipStream(stream, CompressionMode.Decompress))) {
     150          XmlParser parser = new XmlParser(reader);
     151          Deserializer deserializer = new Deserializer(new TypeMapping[] { });
     152          return deserializer.Deserialize(parser);
     153        }
     154      } catch (PersistenceException) {
     155        throw;
     156      } catch (Exception x) {
     157        throw new PersistenceException("Unexpected exception during deserialization", x);
    133158      }
    134159    }
     
    136161    private static object Deserialize(ZipFile zipFile) {
    137162      try {
    138         Deserializer deSerializer = new Deserializer(
    139           ParseTypeCache(
    140           new StreamReader(
    141             zipFile.GetInputStream(zipFile.GetEntry("typecache.xml")))));
     163        ZipEntry typecache = zipFile.GetEntry("typecache.xml");
     164        if (typecache == null)
     165          throw new PersistenceException("file does not contain typecache.xml");
     166        Deserializer deSerializer = new Deserializer(ParseTypeCache(new StreamReader(zipFile.GetInputStream(typecache))));
     167        ZipEntry data = zipFile.GetEntry("data.xml");
     168        if (data == null)
     169          throw new PersistenceException("file does not contain data.xml");
    142170        XmlParser parser = new XmlParser(
    143           new StreamReader(zipFile.GetInputStream(zipFile.GetEntry("data.xml"))));
     171          new StreamReader(zipFile.GetInputStream(data)));
    144172        object result = deSerializer.Deserialize(parser);
    145173        zipFile.Close();
    146174        return result;
    147       } catch (PersistenceException e) {
     175      } catch (PersistenceException) {
    148176        throw;
    149177      } catch (Exception e) {
  • trunk/sources/HeuristicLab.Persistence/3.3/HeuristicLab.Persistence-3.3.csproj

    r2994 r3005  
    106106    <Compile Include="Core\FormatBase.cs" />
    107107    <Compile Include="Auxiliary\TypeExtensions.cs" />
     108    <Compile Include="Core\Tokens\TypeToken.cs" />
    108109    <Compile Include="Core\TypeMapping.cs" />
    109110    <Compile Include="Auxiliary\TypeName.cs" />
  • trunk/sources/HeuristicLab.Persistence/3.3/Tests/UseCases.cs

    r2994 r3005  
    199199    [TestMethod]
    200200    public void ComplexStorable() {
    201       Root r = new Root();
    202       r.intStack.Push(1);
    203       r.intStack.Push(2);
    204       r.intStack.Push(3);
    205       r.selfReferences = new List<Root> { r, r };
    206       r.c = new Custom { r = r };
    207       r.dict.Add("one", 1);
    208       r.dict.Add("two", 2);
    209       r.dict.Add("three", 3);
    210       r.myEnum = TestEnum.va1;
    211       r.i = new[] { 7, 5, 6 };
    212       r.s = "new value";
    213       r.intArray = new ArrayList { 3, 2, 1 };
    214       r.intList = new List<int> { 9, 8, 7 };
    215       r.multiDimArray = new double[,] { { 5, 4, 3 }, { 1, 4, 6 } };
    216       r.boolean = false;
    217       r.dateTime = DateTime.Now;
    218       r.kvp = new KeyValuePair<string, int>("string key", 321);
    219       r.uninitialized = null;
     201      Root r = InitializeComplexStorable();
    220202      XmlGenerator.Serialize(r, tempFile);
    221203      Root newR = (Root)XmlParser.Deserialize(tempFile);
     204      CompareComplexStorables(r, newR);
     205    }
     206
     207    private static void CompareComplexStorables(Root r, Root newR) {
    222208      Assert.AreEqual(
    223209        DebugStringGenerator.Serialize(r),
     
    274260    }
    275261
     262    private static Root InitializeComplexStorable() {
     263      Root r = new Root();
     264      r.intStack.Push(1);
     265      r.intStack.Push(2);
     266      r.intStack.Push(3);
     267      r.selfReferences = new List<Root> { r, r };
     268      r.c = new Custom { r = r };
     269      r.dict.Add("one", 1);
     270      r.dict.Add("two", 2);
     271      r.dict.Add("three", 3);
     272      r.myEnum = TestEnum.va1;
     273      r.i = new[] { 7, 5, 6 };
     274      r.s = "new value";
     275      r.intArray = new ArrayList { 3, 2, 1 };
     276      r.intList = new List<int> { 9, 8, 7 };
     277      r.multiDimArray = new double[,] { { 5, 4, 3 }, { 1, 4, 6 } };
     278      r.boolean = false;
     279      r.dateTime = DateTime.Now;
     280      r.kvp = new KeyValuePair<string, int>("string key", 321);
     281      r.uninitialized = null;
     282
     283      return r;
     284    }
     285
    276286    [TestMethod]
    277287    public void SelfReferences() {
     
    762772    }
    763773
     774    [TestMethod]
     775    public void TestStreaming() {
     776      using (MemoryStream stream = new MemoryStream()) {
     777        Root r = InitializeComplexStorable();
     778        XmlGenerator.Serialize(r, stream);
     779        using (MemoryStream stream2 = new MemoryStream(stream.ToArray())) {
     780          Root newR = (Root)XmlParser.Deserialize(stream2);
     781          CompareComplexStorables(r, newR);
     782        }
     783      }
     784    }
     785
    764786    [ClassInitialize]
    765787    public static void Initialize(TestContext testContext) {
Note: See TracChangeset for help on using the changeset viewer.