2014-10-06 2 views
1

У меня есть миллиарды объектов, которые я пытаюсь структурировать в дереве B +, сериализованном на HDD. Я использую библиотеку BPlusTree для структуры данных и protobuf-net для сериализации/десериализации. В связи с этим я определяю свои классы как:Protobuf-net запрашивает TypeModel.CS при использовании с Generics для десериализации

[ProtoContract] 
    public class B<C, M> 
     where C : IComparable<C> 
     where M : IData<C> 
    { 
     internal B() 
     { 
      lambda = new List<Lambda<C, M>>(); 
      omega = 0; 
     } 

     internal B(C coordinate) 
     { 
      lambda = new List<Lambda<C, M>>(); 
      e = coordinate; 
      omega = 0; 
     } 

     [ProtoMember(1)] 
     internal C e { set; get; } 

     [ProtoMember(2)] 
     internal List<Lambda<C, M>> lambda { private set; get; } 

     [ProtoMember(3)] 
     internal int omega { set; get; } 
    } 


[ProtoContract] 
public class Lambda<C, M> 
    where C : IComparable<C> 
    where M : IData<C> 
{ 
    internal Lambda() { } 

    internal Lambda(char tau, M atI) 
    { 
     this.tau = tau; 
     this.atI = atI; 
    } 

    [ProtoMember(1)] 
    internal char tau { private set; get; } 

    [ProtoMember(2)] 
    internal M atI { private set; get; } 
} 

и определяю мои сериализаторы/deserializers следующим образом:

public class BSerializer<C, M> : ISerializer<B<C, M>> 
     where C : IComparable<C> 
     where M : IData<C> 
    { 
     public B<C, M> ReadFrom(System.IO.Stream stream) 
     { 
      return Serializer.Deserialize<B<C, M>>(stream); 
     } 

     public void WriteTo(B<C, M> value, System.IO.Stream stream) 
     { 
      Serializer.Serialize<B<C, M>>(stream, value); 
     } 
    } 

Затем я использую их все в B + Tree (This library) структуры данных, которая определяется как:

var options = new BPlusTree<C, B<C, M>>.OptionsV2(CSerializer, BSerializer); 
var myTree = new BPlusTree<C, B<C, M>>(options); 

Дерево B + определяется как словарь пар ключ-значение. Мой key (т. Е. C) является целым числом, а сериализатор является сериализатором по умолчанию библиотеки BPlusTree. Мой Value - это настраиваемый объект B<C,M>, который сериализуется с использованием protobuf-net.

Моя проблема, конечно, происходит, но почти в случайные моменты времени; всегда ищет Keys, он неожиданно начинает десериализацию Value и при первом вызове B<C, M> ReadFrom(System.IO.Stream stream) запрашивает TypeModel.CS и ProtoReader.CS файлов. Я получаю оба пакета от NuGet.

+0

запрашивает файл просто означает, что перехвачено исключение, и у вас есть отладочные символы; каково фактическое сообщение об исключении? –

+0

@MarcGravell исключение: 'Неверное поле в исходных данных: 0' – Hamed

+0

, что * обычно * означает, что фактические данные недействительны - каков более широкий контекст здесь? от чего вы сериализуете/десериализуете? –

ответ

2

Проверка кода, похоже, что код вызова предполагает, что сериализация знает о своей собственной длине; от источника:

foreach (T i in items) 
    _serializer.WriteTo(i, io); 

сообщений Protobuf не самоограниченный - спецификация Google Protobuf определяет добавления === слияния. Таким образом, вам нужно будет префикс сообщений. К счастью, вы должны просто переключиться на SerializeWithLengthPrefix и DeserializeWithLengthPrefix. Если это не сработает, было бы целесообразно собрать полностью воспроизводимый пример, чтобы его можно было исследовать.

+0

Спасибо, действительно, @MarcGravell, это спасло меня после почти 10 дней назад и вперед по моему адскому кодексу, подозревая почти все (вы не поверите мне, что я подозреваю также, что наследование и полиморфизм ;-)) Спасибо. – Hamed

+0

@ Hamed ничего себе, это исправить? Я знал, что код вызова был проблематичным, но я доволен и несколько удивлен, если это единственная точка боли ... –

+0

Да, это решило «большой» вопрос :) На этот раз он продолжает давать «Попытка прочитать за концом потока, который, предположительно, станет следующим кошмаром (я надеюсь, что НЕ): D – Hamed

2

В качестве альтернативного подхода к решению этой проблемы, вы можете также агрегировать поведение встроенных serailizers:

class BSerializer<C, M> : ISerializer<B<C, M>> 
     where C : IComparable<C> 
     where M : IData<C> 
    { 
     public B<C, M> ReadFrom(System.IO.Stream stream) 
     { 
      byte[] value = CSharpTest.Net.Serialization.PrimitiveSerializer.Bytes.ReadFrom(stream); 
      return Serializer.Deserialize<B<C, M>>(new MemoryStream(value)); 
     } 

     public void WriteTo(B<C, M> value, System.IO.Stream stream) 
     { 
      using (var memory = new MemoryStream()) 
      { 
       Serializer.Serialize<B<C, M>>(memory, value); 
       CSharpTest.Net.Serialization.PrimitiveSerializer.Bytes.WriteTo(memory.ToArray(), stream); 
      } 
     } 
    } 

Примечание: Этот подход может быть проблемой производительности из-за ненужные копии данных; однако это может помочь решить проблему.

Другая возможность - это просто определить дерево как BPlusTree<TKey, byte[]> и предоставить PrimitiveSerializer.Bytes в качестве сериализатора значений. Это ставит бремя сериализации объекта на вызывающего абонента, что может быть очень хорошим. Причина, по которой это может быть выгодным, в два раза:

  1. Ваша объектная модель больше не обязательна быть неизменной.
  2. Если десериализация объекта стоит дорого, это может работать лучше при использовании с произвольным доступом.

Для других общих проблем сериализации и некоторые примеры, пожалуйста, прочитайте следующую статью:

http://csharptest.net/1230/bplustree-and-custom-iserializer-implementations/

+0

Я согласен с вашей точкой «ненужные копии» для первого решения, я также думаю, что вторая идея хороша. Тем не менее, у меня есть небольшая проблема: могу ли я назвать это двухэтапной (де) сериализацией, которая является (1) моим значением объекта 'byte []' и (2) serialize 'byte []'? – Hamed

+0

@Hamed Вы завершаете сериализацию в байт [], чтобы поместить его, и десериализовать из байта [] при чтении. –

+0

мои извинения заранее ... но не могли бы вы помочь мне понять, как я могу «завершить сериализацию до' byte [] '" без использования 'Formatter'? – Hamed

Смежные вопросы