avro-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cutt...@apache.org
Subject svn commit: r1527061 - in /avro/trunk: ./ lang/csharp/ lang/csharp/src/apache/main/ lang/csharp/src/apache/main/File/ lang/csharp/src/apache/main/Generic/ lang/csharp/src/apache/main/Specific/ lang/csharp/src/apache/test/File/ lang/csharp/src/apache/te...
Date Fri, 27 Sep 2013 20:27:15 GMT
Author: cutting
Date: Fri Sep 27 20:27:15 2013
New Revision: 1527061

URL: http://svn.apache.org/r1527061
Log:
AVRO-1332. C#: Improve DatumReader performance. Contributed by David McIntosh.

Modified:
    avro/trunk/CHANGES.txt
    avro/trunk/lang/csharp/Avro.sln
    avro/trunk/lang/csharp/build.sh
    avro/trunk/lang/csharp/src/apache/main/Avro.main.csproj
    avro/trunk/lang/csharp/src/apache/main/File/DataFileReader.cs
    avro/trunk/lang/csharp/src/apache/main/Generic/DatumReader.cs
    avro/trunk/lang/csharp/src/apache/main/Specific/ObjectCreator.cs
    avro/trunk/lang/csharp/src/apache/test/File/FileTests.cs
    avro/trunk/lang/csharp/src/apache/test/Generic/GenericTests.cs
    avro/trunk/lang/csharp/src/apache/test/Specific/SpecificTests.cs

Modified: avro/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/avro/trunk/CHANGES.txt?rev=1527061&r1=1527060&r2=1527061&view=diff
==============================================================================
--- avro/trunk/CHANGES.txt (original)
+++ avro/trunk/CHANGES.txt Fri Sep 27 20:27:15 2013
@@ -11,6 +11,9 @@ Trunk (not yet released)
     AVRO-1355. Java: Reject schemas with duplicate field
     names. (Christophe Taton via cutting)
 
+    AVRO-1332. C#: Improve DatumReader performance.
+    (David McIntosh via cutting)
+
   BUG FIXES
 
     AVRO-1368. Fix SpecificDatumWriter to, when writing a string

Modified: avro/trunk/lang/csharp/Avro.sln
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/Avro.sln?rev=1527061&r1=1527060&r2=1527061&view=diff
==============================================================================
--- avro/trunk/lang/csharp/Avro.sln (original)
+++ avro/trunk/lang/csharp/Avro.sln Fri Sep 27 20:27:15 2013
@@ -14,6 +14,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avro.msbuild", "src\apache\msbuild\Avro.msbuild.csproj", "{AEB22F94-4ECF-4008-B159-389B3F05D54B}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avro.perf", "src\apache\perf\Avro.perf.csproj", "{AC4E1909-2594-4D01-9B2B-B832C07BAFE5}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -76,6 +78,16 @@ Global
 		{AEB22F94-4ECF-4008-B159-389B3F05D54B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
 		{AEB22F94-4ECF-4008-B159-389B3F05D54B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
 		{AEB22F94-4ECF-4008-B159-389B3F05D54B}.Release|x86.ActiveCfg = Release|Any CPU
+		{AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Release|x86.ActiveCfg = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

Modified: avro/trunk/lang/csharp/build.sh
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/build.sh?rev=1527061&r1=1527060&r2=1527061&view=diff
==============================================================================
--- avro/trunk/lang/csharp/build.sh (original)
+++ avro/trunk/lang/csharp/build.sh Fri Sep 27 20:27:15 2013
@@ -33,6 +33,11 @@ case "$1" in
 	nunit-console Avro.nunit
 	;;
 
+    perf)
+	xbuild
+	mono build/perf/Release/Avro.perf.exe
+	;;
+
     dist)
         # build binary tarball
 	xbuild
@@ -51,7 +56,7 @@ case "$1" in
 	;;
 
     *)
-        echo "Usage: $0 {test|clean}"
+        echo "Usage: $0 {test|clean|dist|perf}"
         exit 1
 esac
 

Modified: avro/trunk/lang/csharp/src/apache/main/Avro.main.csproj
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Avro.main.csproj?rev=1527061&r1=1527060&r2=1527061&view=diff
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Avro.main.csproj (original)
+++ avro/trunk/lang/csharp/src/apache/main/Avro.main.csproj Fri Sep 27 20:27:15 2013
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
@@ -101,11 +101,15 @@
     <Compile Include="File\NullCodec.cs" />
     <Compile Include="Generic\DatumReader.cs" />
     <Compile Include="Generic\DatumWriter.cs" />
+    <Compile Include="Generic\GenericDatumReader.cs" />
+    <Compile Include="Generic\GenericDatumWriter.cs" />
     <Compile Include="Generic\GenericEnum.cs" />
     <Compile Include="Generic\GenericFixed.cs" />
     <Compile Include="Generic\GenericReader.cs" />
     <Compile Include="Generic\GenericRecord.cs" />
     <Compile Include="Generic\GenericWriter.cs" />
+    <Compile Include="Generic\PreresolvingDatumReader.cs" />
+    <Compile Include="Generic\PreresolvingDatumWriter.cs" />
     <Compile Include="IO\BinaryDecoder.cs" />
     <Compile Include="IO\BinaryEncoder.cs" />
     <Compile Include="IO\ByteBufferInputStream.cs" />
@@ -138,9 +142,11 @@
     <Compile Include="Schema\SchemaParseException.cs" />
     <Compile Include="Schema\UnionSchema.cs" />
     <Compile Include="Schema\UnnamedSchema.cs" />
+    <Compile Include="Specific\SpecificDatumWriter.cs" />
     <Compile Include="Specific\SpecificException.cs" />
     <Compile Include="Specific\SpecificProtocol.cs" />
     <Compile Include="Specific\ObjectCreator.cs" />
+    <Compile Include="Specific\SpecificDatumReader.cs" />
     <Compile Include="Specific\SpecificFixed.cs" />
     <Compile Include="Specific\SpecificReader.cs" />
     <Compile Include="Specific\SpecificWriter.cs" />
@@ -171,4 +177,4 @@
   <Target Name="AfterBuild">
   </Target>
   -->
-</Project>
+</Project>
\ No newline at end of file

Modified: avro/trunk/lang/csharp/src/apache/main/File/DataFileReader.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/File/DataFileReader.cs?rev=1527061&r1=1527060&r2=1527061&view=diff
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/File/DataFileReader.cs (original)
+++ avro/trunk/lang/csharp/src/apache/main/File/DataFileReader.cs Fri Sep 27 20:27:15 2013
@@ -27,6 +27,8 @@ namespace Avro.File
 {
     public class DataFileReader<T> : IFileReader<T>
     {
+        public delegate DatumReader<T> CreateDatumReader(Schema writerSchema, Schema readerSchema);
+
         private DatumReader<T> _reader;
         private Decoder _decoder, _datumDecoder;
         private Header _header;
@@ -39,6 +41,7 @@ namespace Avro.File
         private long _blockStart;
         private Stream _stream;
         private Schema _readerSchema;
+        private readonly CreateDatumReader _datumReaderFactory;
 
         /// <summary>
         ///  Open a reader for a file using path
@@ -71,12 +74,23 @@ namespace Avro.File
         }
 
         /// <summary>
-        ///  Open a reader for a stream and using the reader's schema
+        ///  Open a reader for a stream using the reader's schema
         /// </summary>
         /// <param name="inStream"></param>
         /// <returns></returns>
         public static IFileReader<T> OpenReader(Stream inStream, Schema readerSchema)
         {
+            return OpenReader(inStream, readerSchema, CreateDefaultReader);
+        }
+
+
+        /// <summary>
+        ///  Open a reader for a stream using the reader's schema and a custom DatumReader
+        /// </summary>
+        /// <param name="inStream"></param>
+        /// <returns></returns>
+        public static IFileReader<T> OpenReader(Stream inStream, Schema readerSchema, CreateDatumReader datumReaderFactory)
+        {
             if (!inStream.CanSeek)
                 throw new AvroRuntimeException("Not a valid input stream - must be seekable!");
 
@@ -90,14 +104,15 @@ namespace Avro.File
             inStream.Seek(0, SeekOrigin.Begin);
 
             if (magic.SequenceEqual(DataFileConstants.Magic))   // current format
-                return new DataFileReader<T>(inStream, readerSchema);         // (not supporting 1.2 or below, format) 
+                return new DataFileReader<T>(inStream, readerSchema, datumReaderFactory);         // (not supporting 1.2 or below, format) 
 
             throw new AvroRuntimeException("Not an Avro data file");
         }
 
-        DataFileReader(Stream stream, Schema readerSchema)
+        DataFileReader(Stream stream, Schema readerSchema, CreateDatumReader datumReaderFactory)
         {
             _readerSchema = readerSchema;
+            _datumReaderFactory = datumReaderFactory;
             Init(stream);
             BlockFinished();
         }
@@ -288,22 +303,22 @@ namespace Avro.File
 
             // parse schema and set codec 
             _header.Schema = Schema.Parse(GetMetaString(DataFileConstants.MetaDataSchema));
-            _reader = GetReaderFromSchema();
+            _reader = _datumReaderFactory(_header.Schema, _readerSchema ?? _header.Schema);
             _codec = ResolveCodec();
         }
 
-        private DatumReader<T> GetReaderFromSchema()
+        private static DatumReader<T> CreateDefaultReader(Schema writerSchema, Schema readerSchema)
         {
             DatumReader<T> reader = null;
             Type type = typeof(T);
 
             if (typeof(ISpecificRecord).IsAssignableFrom(type))
             {
-                reader = new SpecificReader<T>(_header.Schema, _readerSchema ?? _header.Schema);
+                reader = new SpecificReader<T>(writerSchema, readerSchema);
             }
             else // generic
             {
-                reader = new GenericReader<T>(_header.Schema, _readerSchema ?? _header.Schema);
+                reader = new GenericReader<T>(writerSchema, readerSchema);
             }
             return reader;
         }

Modified: avro/trunk/lang/csharp/src/apache/main/Generic/DatumReader.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/DatumReader.cs?rev=1527061&r1=1527060&r2=1527061&view=diff
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/DatumReader.cs (original)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/DatumReader.cs Fri Sep 27 20:27:15 2013
@@ -33,293 +33,4 @@ namespace Avro.Generic
         /// </summary>        
         T Read(T reuse, Decoder decoder);
     }
-
-    ///// <summary>
-    ///// Deserialize Avro-encoded data into a .net data structure.
-    ///// </summary>
-    //public class DatumReader
-    //{
-    //    public Schema WriterSchema { get; private set; }
-    //    public Schema ReaderSchema { get; private set; }
-
-    //    /// <summary>
-    //    /// As defined in the Avro specification, we call the schema encoded
-    //    /// in the data the "writer's schema", and the schema expected by the
-    //    /// reader the "reader's schema".
-    //    /// </summary>
-    //    /// <param name="writerSchema"></param>
-    //    /// <param name="readerSchema"></param>
-    //    public DatumReader(Schema writerSchema, Schema readerSchema)
-    //    {
-    //        if (null == writerSchema) throw new ArgumentNullException("writerSchema", "writerSchema cannot be null.");
-    //        if (null == readerSchema) throw new ArgumentNullException("readerSchema", "readerSchema cannot be null.");
-
-    //        this.WriterSchema = writerSchema;
-    //        this.ReaderSchema = readerSchema;
-    //    }
-
-
-    //    static bool checkProps(Schema a, Schema b, params string[] props)
-    //    {
-    //        foreach (string prop in props)
-    //        {
-    //            if (!string.Equals(a[prop], b[prop]))
-    //                return false;
-    //        }
-
-    //        return true;
-    //    }
-    //    //static bool CheckProps(Schema schema_one, Schema schema_two, IEnumerable<string> props)
-    //    //{
-
-    //    //}
-
-    //    static bool matchSchemas(Schema writers_schema, Schema readers_schema)
-    //    {
-    //        string w_type = writers_schema.Type, r_type = readers_schema.Type;
-
-    //        if (string.Equals(Schema.UNION, w_type) || string.Equals(Schema.UNION, r_type))
-    //            return true;
-    //        else if (PrimitiveSchema.PrimitiveKeyLookup.ContainsKey(w_type) && PrimitiveSchema.PrimitiveKeyLookup.ContainsKey(r_type) && w_type == r_type)
-    //            return true;
-    //        else if (w_type == Schema.RECORD && r_type == Schema.RECORD && DatumReader.checkProps(writers_schema, readers_schema, "fullname"))
-    //            return true;
-    //        else if (w_type == "error" && r_type == "error" && DatumReader.checkProps(writers_schema, readers_schema, "fullname"))
-    //            return true;
-    //        else if (w_type == "request" && r_type == "request")
-    //            return true;
-    //        else if (w_type == Schema.FIXED && r_type == Schema.FIXED && DatumReader.checkProps(writers_schema, readers_schema, "fullname", "size"))
-    //            return true;
-    //        else if (w_type == Schema.ENUM && r_type == Schema.ENUM && DatumReader.checkProps(writers_schema, readers_schema, "fullname"))
-    //            return true;
-    //        //else if (w_type == Schema.MAP && r_type == Schema.MAP && DatumReader.CheckProps(writers_schema.values, readers_schema.values, "type"))
-    //        //    return true;
-    //        //else if (w_type == Schema.ARRAY && r_type == Schema.ARRAY && DatumReader.check_props(writers_schema.items, readers_schema.items, "type"))
-    //        //    return true;
-    //        else if (w_type == Schema.INT && Util.checkIsValue(r_type, Schema.LONG, Schema.FLOAT, Schema.DOUBLE))
-    //            return true;
-    //        else if (w_type == Schema.LONG && Util.checkIsValue(r_type, Schema.FLOAT, Schema.DOUBLE))
-    //            return true;
-    //        else if (w_type == Schema.FLOAT && r_type == Schema.DOUBLE)
-    //            return true;
-
-    //        if (Util.checkIsValue(w_type, Schema.MAP, Schema.ARRAY))
-    //            throw new NotImplementedException(w_type);
-
-    //        return false;
-    //    }
-
-    //    public object Read(BinaryDecoder decoder)
-    //    {
-    //        if (null == this.ReaderSchema)
-    //            this.ReaderSchema = this.WriterSchema;
-
-    //        return ReadData(this.WriterSchema, this.ReaderSchema, decoder);
-
-    //    }
-
-    //    private object ReadData(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
-    //    {
-    //        if (!matchSchemas(writers_schema, readers_schema))
-    //            throw new SchemaResolutionException("Schemas do not match.", writers_schema, readers_schema);
-
-    //        if (writers_schema.Type != Schema.UNION && readers_schema.Type == Schema.UNION)
-    //        {
-    //            foreach (Schema s in ((UnionSchema)readers_schema).Schemas)
-    //            {
-    //                if (DatumReader.matchSchemas(writers_schema, s))
-    //                {
-    //                    return ReadData(writers_schema, s, decoder);
-    //                }
-    //            }
-
-    //            throw new SchemaResolutionException("Schemas do not match.", writers_schema, readers_schema);
-    //        }
-
-    //        if (writers_schema.Type == Schema.NULL)
-    //            return decoder.ReadNull();
-    //        else if (writers_schema.Type == Schema.BOOLEAN)
-    //            return decoder.ReadBool();
-    //        else if (writers_schema.Type == Schema.STRING)
-    //            return decoder.ReadUTF8();
-    //        else if (writers_schema.Type == Schema.INT)
-    //            return decoder.ReadInt();
-    //        else if (writers_schema.Type == Schema.LONG)
-    //            return decoder.ReadLong();
-    //        else if (writers_schema.Type == Schema.FLOAT)
-    //            return decoder.ReadFloat();
-    //        else if (writers_schema.Type == Schema.DOUBLE)
-    //            return decoder.ReadDouble();
-    //        else if (writers_schema.Type == Schema.BYTES)
-    //            return decoder.ReadBytes();
-    //        else if (writers_schema.Type == Schema.FIXED)
-    //            return ReadFixed(writers_schema, readers_schema, decoder);
-    //        else if (writers_schema.Type == Schema.ENUM)
-    //            return ReadEnum(writers_schema, readers_schema, decoder);
-    //        else if (writers_schema.Type == Schema.ARRAY)
-    //            return ReadArray(writers_schema, readers_schema, decoder);
-    //        else if (writers_schema.Type == Schema.MAP)
-    //            return ReadMap(writers_schema, readers_schema, decoder);
-    //        else if (writers_schema.Type == Schema.UNION)
-    //            return ReadUnion(writers_schema, readers_schema, decoder);
-    //        else if (Util.checkIsValue(writers_schema.Type, Schema.RECORD, "error", "request"))
-    //            return ReadRecord(writers_schema, readers_schema, decoder);
-    //        else
-    //            throw new AvroException("Cannot Read unknown type type) " + writers_schema.Type);
-    //    }
-
-    //    public void SkipData(Schema writers_schema, BinaryDecoder decoder)
-    //    {
-    //        if (writers_schema.Type == Schema.NULL)
-    //            decoder.SkipNull();
-    //        else if (writers_schema.Type == Schema.BOOLEAN)
-    //            decoder.SkipBoolean();
-    //        else if (writers_schema.Type == Schema.STRING)
-    //            decoder.SkipUTF8();
-    //        else if (writers_schema.Type == Schema.INT)
-    //            decoder.SkipInt();
-    //        else if (writers_schema.Type == Schema.LONG)
-    //            decoder.SkipLong();
-    //        else if (writers_schema.Type == Schema.FLOAT)
-    //            decoder.SkipFloat();
-    //        else if (writers_schema.Type == Schema.DOUBLE)
-    //            decoder.SkipDouble();
-    //        else if (writers_schema.Type == Schema.BYTES)
-    //            decoder.ReadBytes();
-    //        else if (writers_schema.Type == Schema.FIXED)
-    //            SkipFixed(writers_schema as FixedSchema, decoder);
-    //        else if (writers_schema.Type == Schema.ENUM)
-    //            SkipEnum(writers_schema, decoder);
-    //        else if (writers_schema.Type == Schema.ARRAY)
-    //            SkipArray(writers_schema as ArraySchema, decoder);
-    //        else if (writers_schema.Type == Schema.MAP)
-    //            SkipMap(writers_schema as MapSchema, decoder);
-    //        else if (writers_schema.Type == Schema.UNION)
-    //            SkipUnion(writers_schema as UnionSchema, decoder);
-    //        else if (Util.checkIsValue(writers_schema.Type, Schema.RECORD, "error", "request"))
-    //            SkipRecord(writers_schema as RecordSchema, decoder);
-    //        else
-    //            throw new AvroException("Unknown type type: %s" + writers_schema.Type);
-
-    //    }
-
-    //    private void SkipRecord(RecordSchema writers_schema, BinaryDecoder decoder)
-    //    {
-    //        foreach (Field field in writers_schema.Fields)
-    //            SkipData(field.Schema, decoder);
-    //    }
-
-    //    private void SkipUnion(UnionSchema writers_schema, BinaryDecoder decoder)
-    //    {
-    //        int index_of_schema = (int)decoder.ReadLong();
-    //        SkipData(writers_schema.Schemas[index_of_schema], decoder);
-    //    }
-
-    //    private void SkipMap(MapSchema writers_schema, BinaryDecoder decoder)
-    //    {
-    //        long block_count = decoder.ReadLong();
-    //        while (block_count != 0)
-    //        {
-    //            if (block_count < 0)
-    //            {
-    //                long block_size = decoder.ReadLong();
-    //                decoder.skip(block_size);
-    //            }
-    //            else
-    //            {
-    //                for (int i = 0; i < block_count; i++)
-    //                {
-    //                    decoder.SkipUTF8();
-    //                    SkipData(writers_schema.Values, decoder);
-    //                    block_count = decoder.ReadLong();
-    //                }
-    //            }
-    //        }
-    //    }
-
-    //    private void SkipArray(ArraySchema writers_schema, BinaryDecoder decoder)
-    //    {
-    //        long block_count = decoder.ReadLong();
-    //        while (block_count != 0)
-    //        {
-    //            if (block_count < 0)
-    //            {
-    //                long block_size = decoder.ReadLong();
-    //                decoder.skip(block_size);
-    //            }
-    //            else
-    //            {
-    //                for (int i = 0; i < block_count; i++)
-    //                {
-    //                    decoder.SkipUTF8();
-    //                    SkipData(writers_schema.Items, decoder);
-    //                    block_count = decoder.ReadLong();
-    //                }
-    //            }
-    //        }
-    //    }
-
-    //    private void SkipEnum(Schema writers_schema, BinaryDecoder decoder)
-    //    {
-    //        decoder.SkipInt();
-    //    }
-
-    //    private void SkipFixed(FixedSchema writers_schema, BinaryDecoder decoder)
-    //    {
-    //        decoder.skip(writers_schema.Size);
-    //    }
-
-    //    /// <summary>
-    //    /// A record is encoded by encoding the values of its fields
-    //    /// in the order that they are declared. In other words, a record
-    //    /// is encoded as just the concatenation of the encodings of its fields.
-    //    /// Field values are encoded per their schema.
-
-    //    /// Schema Resolution:
-    //    ///  * the ordering of fields may be different: fields are matched by name.
-    //    ///  * schemas for fields with the same name in both records are resolved
-    //    ///    recursively.
-    //    ///  * if the writer's record contains a field with a name not present in the
-    //    ///    reader's record, the writer's value for that field is ignored.
-    //    ///  * if the reader's record schema has a field that contains a default value,
-    //    ///    and writer's schema does not have a field with the same name, then the
-    //    ///    reader should use the default value from its field.
-    //    ///  * if the reader's record schema has a field with no default value, and 
-    //    ///    writer's schema does not have a field with the same name, then the
-    //    ///    field's value is unset.
-    //    /// </summary>
-    //    /// <param name="writers_schema"></param>
-    //    /// <param name="readers_schema"></param>
-    //    /// <param name="decoder"></param>
-    //    /// <returns></returns>
-    //    private object ReadRecord(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
-    //    {
-    //        throw new NotImplementedException();
-    //    }
-
-    //    private object ReadUnion(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
-    //    {
-    //        throw new NotImplementedException();
-    //    }
-
-    //    private object ReadMap(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
-    //    {
-    //        throw new NotImplementedException();
-    //    }
-
-    //    private object ReadArray(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
-    //    {
-    //        throw new NotImplementedException();
-    //    }
-
-    //    private object ReadEnum(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
-    //    {
-    //        throw new NotImplementedException();
-    //    }
-
-    //    private object ReadFixed(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
-    //    {
-    //        throw new NotImplementedException();
-    //    }
-    //}
 }

Modified: avro/trunk/lang/csharp/src/apache/main/Specific/ObjectCreator.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Specific/ObjectCreator.cs?rev=1527061&r1=1527060&r2=1527061&view=diff
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Specific/ObjectCreator.cs (original)
+++ avro/trunk/lang/csharp/src/apache/main/Specific/ObjectCreator.cs Fri Sep 27 20:27:15 2013
@@ -314,12 +314,15 @@ namespace Avro.Specific
             NameCtorKey key = new NameCtorKey(name, schemaType);
             
             CtorDelegate ctor;
-            if (!ctors.TryGetValue(key, out ctor))
+            lock(ctors)
             {
-                Type type = GetType(name, schemaType);
-                ctor = GetConstructor(name, schemaType, type);
+                if (!ctors.TryGetValue(key, out ctor))
+                {
+                    Type type = GetType(name, schemaType);
+                    ctor = GetConstructor(name, schemaType, type);
 
-                ctors.Add(key, ctor);
+                    ctors.Add(key, ctor);
+                }
             }
             return ctor();
         }

Modified: avro/trunk/lang/csharp/src/apache/test/File/FileTests.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/test/File/FileTests.cs?rev=1527061&r1=1527060&r2=1527061&view=diff
==============================================================================
--- avro/trunk/lang/csharp/src/apache/test/File/FileTests.cs (original)
+++ avro/trunk/lang/csharp/src/apache/test/File/FileTests.cs Fri Sep 27 20:27:15 2013
@@ -16,6 +16,7 @@
  * limitations under the License.
  */
 using System;
+using System.Collections;
 using System.IO;
 using System.Collections.Generic;
 using Avro.Generic;
@@ -63,32 +64,34 @@ namespace Avro.Test.File
         {
             // create and write out
             IList<Foo> records = MakeRecords(recs);
-            MemoryStream dataFileOutputStream = new MemoryStream();
 
-            Schema schema = Schema.Parse(schemaStr);
-            DatumWriter<Foo> writer = new SpecificWriter<Foo>(schema);
-            using (IFileWriter<Foo> dataFileWriter = DataFileWriter<Foo>.OpenWriter(writer, dataFileOutputStream, Codec.CreateCodec(codecType)))
+            foreach(var rwFactory in SpecificOptions<Foo>())
             {
-                foreach (Foo rec in records)
-                    dataFileWriter.Append(rec);
-            }
+                MemoryStream dataFileOutputStream = new MemoryStream();
+                Schema schema = Schema.Parse(schemaStr);
+                using (IFileWriter<Foo> dataFileWriter = rwFactory.CreateWriter(dataFileOutputStream, schema, Codec.CreateCodec(codecType)))
+                {
+                    foreach (Foo rec in records)
+                        dataFileWriter.Append(rec);
+                }
 
-            MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray());
+                MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray());
 
-            // read back
-            IList<Foo> readRecords = new List<Foo>();
+                // read back
+                IList<Foo> readRecords = new List<Foo>();
 
-            using (IFileReader<Foo> reader = DataFileReader<Foo>.OpenReader(dataFileInputStream))
-            {
-                foreach (Foo rec in reader.NextEntries)
-                    readRecords.Add(rec);
-            }
+                using (IFileReader<Foo> reader = rwFactory.CreateReader(dataFileInputStream, null))
+                {
+                    foreach (Foo rec in reader.NextEntries)
+                        readRecords.Add(rec);
+                }
 
-            // compare objects via Json
-            Assert.AreEqual(records.Count, readRecords.Count);
-            for (int i = 0; i < records.Count; i++)
-            {
-                Assert.AreEqual(records[i].ToString(), readRecords[i].ToString());
+                // compare objects via Json
+                Assert.AreEqual(records.Count, readRecords.Count);
+                for (int i = 0; i < records.Count; i++)
+                {
+                    Assert.AreEqual(records[i].ToString(), readRecords[i].ToString());
+                }
             }
         }
 
@@ -169,25 +172,30 @@ namespace Avro.Test.File
             new object[] { "f1", 100L }, Codec.Type.Null)]
         public void TestGenericData(string schemaStr, object[] value, Codec.Type codecType)
         {
-            // Create and write out
-            MemoryStream dataFileOutputStream = new MemoryStream();
-            WriteGeneric(dataFileOutputStream, Schema.Parse(schemaStr) as RecordSchema,
-                                               mkRecord(value, Schema.Parse(schemaStr) as RecordSchema), codecType);
+            foreach(var rwFactory in GenericOptions<GenericRecord>())
+            {
+                // Create and write out
+                MemoryStream dataFileOutputStream = new MemoryStream();
+                using (var writer = rwFactory.CreateWriter(dataFileOutputStream, Schema.Parse(schemaStr), Codec.CreateCodec(codecType)))
+                {
+                    writer.Append(mkRecord(value, Schema.Parse(schemaStr) as RecordSchema));
+                }
 
-            MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray());
+                MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray());
 
-            // Read back
-            IList<GenericRecord> readFoos = new List<GenericRecord>();
-            using (IFileReader<GenericRecord> reader = DataFileReader<GenericRecord>.OpenReader(dataFileInputStream))
-            {
-                foreach (GenericRecord foo in reader.NextEntries)
+                // Read back
+                IList<GenericRecord> readFoos = new List<GenericRecord>();
+                using (IFileReader<GenericRecord> reader = rwFactory.CreateReader(dataFileInputStream,null))
                 {
-                    readFoos.Add(foo);
+                    foreach (GenericRecord foo in reader.NextEntries)
+                    {
+                        readFoos.Add(foo);
+                    }
                 }
-            }
 
-            Assert.IsTrue((readFoos != null && readFoos.Count > 0),
-                           string.Format(@"Generic object: {0} did not serialise/deserialise correctly", readFoos));
+                Assert.IsTrue((readFoos != null && readFoos.Count > 0),
+                               string.Format(@"Generic object: {0} did not serialise/deserialise correctly", readFoos));
+            }
         }
 
         /// <summary>
@@ -243,14 +251,19 @@ namespace Avro.Test.File
         [TestCase("{\"type\":\"string\"}", "test", Codec.Type.Null)]
         public void TestPrimitiveData(string schemaStr, object value, Codec.Type codecType)
         {
-            MemoryStream dataFileOutputStream = new MemoryStream();
-            Schema schema = Schema.Parse(schemaStr);
-            WriteGeneric(dataFileOutputStream, schema, value, codecType);
+            foreach(var rwFactory in GenericOptions<object>())
+            {
+                MemoryStream dataFileOutputStream = new MemoryStream();
+                using (var writer = rwFactory.CreateWriter(dataFileOutputStream, Schema.Parse(schemaStr), Codec.CreateCodec(codecType)))
+                {
+                    writer.Append(value);
+                }
 
-            MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray());
+                MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray());
 
-            Assert.IsTrue(ReadGeneric(dataFileInputStream, value),
-                          string.Format("Error reading generic data for object: {0}", value));
+                Assert.IsTrue(CheckPrimitive(dataFileInputStream, value, rwFactory.CreateReader),
+                              string.Format("Error reading generic data for object: {0}", value));
+            }
         }
 
         /// <summary>
@@ -524,40 +537,60 @@ namespace Avro.Test.File
             Schema readerSchema = Schema.Parse( "{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"string\"},"
                 +"{\"name\":\"f3\", \"type\":\"string\", \"default\":\"test\"}]}" );
 
-            MemoryStream dataFileOutputStream = new MemoryStream();
+            foreach(var rwFactory in GenericOptions<GenericRecord>())
+            {
+                MemoryStream dataFileOutputStream = new MemoryStream();
 
-            WriteGeneric(dataFileOutputStream, writerSchema, mkRecord(new [] { "f1", "f1val", "f2", "f2val" }, writerSchema), Codec.Type.Null);
+                using (var writer = rwFactory.CreateWriter(dataFileOutputStream, writerSchema, Codec.CreateCodec(Codec.Type.Null)))
+                {
+                    writer.Append(mkRecord(new [] { "f1", "f1val", "f2", "f2val" }, writerSchema));
+                }
 
-            MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray());
+                MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray());
 
-            using (IFileReader<GenericRecord> reader = DataFileReader<GenericRecord>.OpenReader(dataFileInputStream, readerSchema))
-            {
-                GenericRecord result = reader.Next();
-                object ignore;
-                Assert.IsFalse(result.TryGetValue("f2", out ignore));
-                Assert.AreEqual("f1val", result["f1"]);
-                Assert.AreEqual("test", result["f3"]);
+                using (IFileReader<GenericRecord> reader = rwFactory.CreateReader(dataFileInputStream, readerSchema))
+                {
+                    GenericRecord result = reader.Next();
+                    object ignore;
+                    Assert.IsFalse(result.TryGetValue("f2", out ignore));
+                    Assert.AreEqual("f1val", result["f1"]);
+                    Assert.AreEqual("test", result["f3"]);
+                }
             }
         }
 
-        private bool ReadGeneric<T>(Stream input, T value)
+        private bool CheckPrimitive<T>(Stream input, T value, ReaderWriterPair<T>.ReaderFactory createReader)
         {
-            IFileReader<T> reader = DataFileReader<T>.OpenReader(input);
+            IFileReader<T> reader = createReader(input, null);
             IList<T> readFoos = new List<T>();
             foreach (T foo in reader.NextEntries)
             {
                 readFoos.Add(foo);
             }
-            return (readFoos != null && readFoos.Count > 0);
+            return (readFoos.Count > 0 && 
+                CheckPrimitiveEquals(value, readFoos[0]));
         }
 
-        private void WriteGeneric<T>(Stream output, Schema schema, T value, Codec.Type codecType)
+        private bool CheckPrimitiveEquals(object first, object second)
         {
-            DatumWriter<T> writer = new GenericWriter<T>(schema);
-            using (IFileWriter<T> dataFileWriter = DataFileWriter<T>.OpenWriter(writer, output, Codec.CreateCodec(codecType)))
+            if (first is IList)
             {
-                dataFileWriter.Append(value);
+                var firstList = (IList) first;
+                var secondList = (IList) second;
+                if (firstList.Count != secondList.Count)
+                {
+                    return false;
+                }
+                for (int i = 0; i < firstList.Count; i++)
+                {
+                    if (!CheckPrimitiveEquals(firstList[i], secondList[i]))
+                    {
+                        return false;
+                    }
+                }
+                return true;
             }
+            return (first == null && second == null) || (first.Equals(second));
         }
 
         private static GenericRecord mkRecord(object[] kv, RecordSchema s)
@@ -650,6 +683,51 @@ namespace Avro.Test.File
                                   new object[] {"JJ", 14}, new object[] { "Bill", 90 }, new object[] { "Larry", 4 },
                                   new object[] {"Jenny", 3}, new object[] { "Bob", 9 }, new object[] { null, 48 }};
         }
+
+        private static IEnumerable<ReaderWriterPair<T>> SpecificOptions<T>()
+        {
+            yield return new ReaderWriterPair<T>
+                             {
+                                 CreateReader = (stream, schema) => DataFileReader<T>.OpenReader(stream, schema),
+                                 CreateWriter = (stream, schema, codec) => 
+                                     DataFileWriter<T>.OpenWriter(new SpecificWriter<T>(schema), stream, codec )
+                             };
+
+            yield return new ReaderWriterPair<T>
+                             {
+                                 CreateReader = (stream, schema) => DataFileReader<T>.OpenReader(stream, schema,
+                                     (ws, rs) => new SpecificDatumReader<T>(ws, rs)),
+                                 CreateWriter = (stream, schema, codec) => 
+                                     DataFileWriter<T>.OpenWriter(new SpecificDatumWriter<T>(schema), stream, codec )
+                             };
+        }
+
+        private static IEnumerable<ReaderWriterPair<T>> GenericOptions<T>()
+        {
+            yield return new ReaderWriterPair<T>
+                             {
+                                 CreateReader = (stream, schema) => DataFileReader<T>.OpenReader(stream, schema),
+                                 CreateWriter = (stream, schema, codec) => 
+                                     DataFileWriter<T>.OpenWriter(new GenericWriter<T>(schema), stream, codec )
+                             };
+
+            yield return new ReaderWriterPair<T>
+                             {
+                                 CreateReader = (stream, schema) => DataFileReader<T>.OpenReader(stream, schema,
+                                     (ws, rs) => new GenericDatumReader<T>(ws, rs)),
+                                 CreateWriter = (stream, schema, codec) => 
+                                     DataFileWriter<T>.OpenWriter(new GenericDatumWriter<T>(schema), stream, codec )
+                             };
+        }
+
+        class ReaderWriterPair<T>
+        {
+            public delegate IFileWriter<T> WriterFactory(Stream stream, Schema writerSchema, Codec codec);
+            public delegate IFileReader<T> ReaderFactory(Stream stream, Schema readerSchema);
+
+            public WriterFactory CreateWriter { get; set; }
+            public ReaderFactory CreateReader { get; set; }
+        }
     }
 
 

Modified: avro/trunk/lang/csharp/src/apache/test/Generic/GenericTests.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/test/Generic/GenericTests.cs?rev=1527061&r1=1527060&r2=1527061&view=diff
==============================================================================
--- avro/trunk/lang/csharp/src/apache/test/Generic/GenericTests.cs (original)
+++ avro/trunk/lang/csharp/src/apache/test/Generic/GenericTests.cs Fri Sep 27 20:27:15 2013
@@ -17,6 +17,7 @@
  */
 using System;
 using System.IO;
+using System.Linq;
 using Avro.IO;
 using System.Collections.Generic;
 using Avro.Generic;
@@ -271,14 +272,12 @@ namespace Avro.Test.Generic
             "[{\"name\":\"f2\",\"type\":\"int\"}]}",
             new object[] { "f2", 100 }, Description = "Missing fields - union")]
         // TODO: Missing fields - record, enum, map, fixed
-        /*  FIXME: Resolution using defaults don't work yet.
         [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" +
             "[{\"name\":\"f1\",\"type\":\"boolean\"}]}",
             new object[] { "f1", true },
             "{\"type\":\"record\",\"name\":\"r\",\"fields\":" +
             "[{\"name\":\"f1\",\"type\":\"boolean\"},{\"name\":\"f2\",\"type\":\"string\",\"default\":\"d\"}]}",
             new object[] { "f1", true, "f2", "d" }, Description = "Default field")]
-         */
         public void TestResolution_record(string ws, object[] actual, string rs, object[] expected)
         {
             TestResolution(ws, mkRecord(actual, Schema.Parse(ws) as RecordSchema), rs,
@@ -432,24 +431,50 @@ namespace Avro.Test.Generic
 
         private static S deserialize<S>(Stream ms, Schema ws, Schema rs)
         {
+            long initialPos = ms.Position;
             GenericReader<S> r = new GenericReader<S>(ws, rs);
             Decoder d = new BinaryDecoder(ms);
             S n = default(S);
             S output = r.Read(n, d);
             Assert.AreEqual(ms.Length, ms.Position); // Ensure we have read everything.
+            checkAlternateDeserializers(output, ms, initialPos, ws, rs);
             return output;
         }
 
-        private static void serialize<T>(string writerSchema, T actual, out Stream ms, out Schema ws)
+        private static void checkAlternateDeserializers<S>(S expected, Stream input, long startPos, Schema ws, Schema rs)
         {
-            ms = new MemoryStream();
+            input.Position = startPos;
+            var reader = new GenericDatumReader<S>(ws, rs);
+            Decoder d = new BinaryDecoder(input);
+            S n = default(S);
+            S output = reader.Read(n, d);
+            Assert.AreEqual(input.Length, input.Position); // Ensure we have read everything.
+            Assert.AreEqual(expected, output);
+        }
+
+        private static void serialize<T>(string writerSchema, T actual, out Stream stream, out Schema ws)
+        {
+            var ms = new MemoryStream();
             Encoder e = new BinaryEncoder(ms);
             ws = Schema.Parse(writerSchema);
             GenericWriter<T> w = new GenericWriter<T>(ws);
             w.Write(actual, e);
             ms.Flush();
             ms.Position = 0;
+            checkAlternateSerializers(ms.ToArray(), actual, ws);
+            stream = ms;
         }
 
+        private static void checkAlternateSerializers<T>(byte[] expected, T value, Schema ws)
+        {
+            var ms = new MemoryStream();
+            var writer = new GenericDatumWriter<T>(ws);
+            var e = new BinaryEncoder(ms);
+            writer.Write(value, e);
+            var output = ms.ToArray();
+            
+            Assert.AreEqual(expected.Length, output.Length);
+            Assert.True(expected.SequenceEqual(output));
+        }
     }
 }

Modified: avro/trunk/lang/csharp/src/apache/test/Specific/SpecificTests.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/test/Specific/SpecificTests.cs?rev=1527061&r1=1527060&r2=1527061&view=diff
==============================================================================
--- avro/trunk/lang/csharp/src/apache/test/Specific/SpecificTests.cs (original)
+++ avro/trunk/lang/csharp/src/apache/test/Specific/SpecificTests.cs Fri Sep 27 20:27:15 2013
@@ -16,15 +16,13 @@
  * limitations under the License.
  */
 using System;
+using System.Collections;
 using System.IO;
-using System.Collections.Generic;
+using System.Linq;
 using NUnit.Framework;
-using Avro;
-using Avro.Generic;
 using Avro.IO;
 using System.CodeDom;
 using System.CodeDom.Compiler;
-using Microsoft.CSharp;
 using Avro.Specific;
 using System.Reflection;
 
@@ -131,7 +129,7 @@ namespace Avro.Test
   com.foo.newRec newrec = new com.foo.newRec();
   newrec.f1 = 1200;
   myMap2.Add(""A"", newrec);
-  myObject = com.foo.MyEnum.B;
+  myObject = myA;
 
   IList<System.Object> o1 = new List<System.Object>();
 
@@ -210,17 +208,12 @@ namespace Avro.Test
             Assert.IsFalse(rec == null);
 
             // serialize
-            var stream = new MemoryStream();
-            var binEncoder = new BinaryEncoder(stream);
-            var writer = new SpecificDefaultWriter(rec.Schema);
-            writer.Write(rec.Schema, rec, binEncoder);
+            var stream = serialize(rec.Schema, rec);
 
             // deserialize
-            stream.Position = 0;
-            var decoder = new BinaryDecoder(stream);
-            var reader = new SpecificDefaultReader(rec.Schema, rec.Schema);
-            var rec2 = (ISpecificRecord)reader.Read(null, rec.Schema, rec.Schema, decoder);
+            var rec2 = deserialize<ISpecificRecord>(stream, rec.Schema, rec.Schema);
             Assert.IsFalse(rec2 == null);
+            AssertSpecificRecordEqual(rec, rec2);
         }
 
         [TestCase]
@@ -229,27 +222,119 @@ namespace Avro.Test
             Schema writerSchema = Schema.Parse("{\"type\":\"record\",\"name\":\"EnumRecord\",\"namespace\":\"Avro.Test\"," + 
                                         "\"fields\":[{\"name\":\"enumType\",\"type\": { \"type\": \"enum\", \"name\": \"EnumType\", \"symbols\": [\"FIRST\", \"SECOND\"]} }]}");
 
-            Schema readerSchema = Schema.Parse("{\"type\":\"record\",\"name\":\"EnumRecord\",\"namespace\":\"Avro.Test\"," + 
-                                        "\"fields\":[{\"name\":\"enumType\",\"type\": { \"type\": \"enum\", \"name\": \"EnumType\", \"symbols\": [\"THIRD\", \"FIRST\", \"SECOND\"]} }]}");
+            var testRecord = new EnumRecord();
 
-
-            EnumRecord testRecord = new EnumRecord();
+            Schema readerSchema = testRecord.Schema;
             testRecord.enumType = EnumType.SECOND;
 
             // serialize
-            var stream = new MemoryStream();
-            var binEncoder = new BinaryEncoder(stream);
-            var writer = new SpecificWriter<EnumRecord>(writerSchema);
-            writer.Write(testRecord, binEncoder);
+            var stream = serialize(writerSchema, testRecord);
 
             // deserialize
-            stream.Position = 0;
-            var decoder = new BinaryDecoder(stream);
-            var reader = new SpecificReader<EnumRecord>(writerSchema, readerSchema);
-            var rec2 = reader.Read(null, decoder);
+            var rec2 = deserialize<EnumRecord>(stream, writerSchema, readerSchema);
             Assert.AreEqual( EnumType.SECOND, rec2.enumType );
         }
+
+        private static S deserialize<S>(Stream ms, Schema ws, Schema rs) where S : class, ISpecificRecord
+        {
+            long initialPos = ms.Position;
+            var r = new SpecificReader<S>(ws, rs);
+            Decoder d = new BinaryDecoder(ms);
+            S output = r.Read(null, d);
+            Assert.AreEqual(ms.Length, ms.Position); // Ensure we have read everything.
+            checkAlternateDeserializers(output, ms, initialPos, ws, rs);
+            return output;
+        }
+
+        private static void checkAlternateDeserializers<S>(S expected, Stream input, long startPos, Schema ws, Schema rs) where S : class, ISpecificRecord
+        {
+            input.Position = startPos;
+            var reader = new SpecificDatumReader<S>(ws, rs);
+            Decoder d = new BinaryDecoder(input);
+            S output = reader.Read(null, d);
+            Assert.AreEqual(input.Length, input.Position); // Ensure we have read everything.
+            AssertSpecificRecordEqual(expected, output);
+        }
+
+        private static Stream serialize<T>(Schema ws, T actual)
+        {
+            var ms = new MemoryStream();
+            Encoder e = new BinaryEncoder(ms);
+            var w = new SpecificWriter<T>(ws);
+            w.Write(actual, e);
+            ms.Flush();
+            ms.Position = 0;
+            checkAlternateSerializers(ms.ToArray(), actual, ws);
+            return ms;
+        }
+
+        private static void checkAlternateSerializers<T>(byte[] expected, T value, Schema ws)
+        {
+            var ms = new MemoryStream();
+            var writer = new SpecificDatumWriter<T>(ws);
+            var e = new BinaryEncoder(ms);
+            writer.Write(value, e);
+            var output = ms.ToArray();
+            
+            Assert.AreEqual(expected.Length, output.Length);
+            Assert.True(expected.SequenceEqual(output));
+        }
+
+        private static void AssertSpecificRecordEqual(ISpecificRecord rec1, ISpecificRecord rec2)
+        {
+            var recordSchema = (RecordSchema) rec1.Schema;
+            for (int i = 0; i < recordSchema.Count; i++)
+            {
+                var rec1Val = rec1.Get(i);
+                var rec2Val = rec2.Get(i);
+                if (rec1Val is ISpecificRecord)
+                {
+                    AssertSpecificRecordEqual((ISpecificRecord)rec1Val, (ISpecificRecord)rec2Val);
+                }
+                else if (rec1Val is IList)
+                {
+                    var rec1List = (IList) rec1Val;
+                    if( rec1List.Count > 0 && rec1List[0] is ISpecificRecord)
+                    {
+                        var rec2List = (IList) rec2Val;
+                        Assert.AreEqual(rec1List.Count, rec2List.Count);
+                        for (int j = 0; j < rec1List.Count; j++)
+                        {
+                            AssertSpecificRecordEqual((ISpecificRecord)rec1List[j], (ISpecificRecord)rec2List[j]);
+                        }
+                    }
+                    else
+                    {
+                        Assert.AreEqual(rec1Val, rec2Val);
+                    }
+                }
+                else if (rec1Val is IDictionary)
+                {
+                    var rec1Dict = (IDictionary) rec1Val;
+                    var rec2Dict = (IDictionary) rec2Val;
+                    Assert.AreEqual(rec2Dict.Count, rec2Dict.Count);
+                    foreach (var key in rec1Dict.Keys)
+                    {
+                        var val1 = rec1Dict[key];
+                        var val2 = rec2Dict[key];
+                        if (val1 is ISpecificRecord)
+                        {
+                            AssertSpecificRecordEqual((ISpecificRecord)val1, (ISpecificRecord)val2);
+                        }
+                        else
+                        {
+                            Assert.AreEqual(val1, val2);
+                        }
+                    }
+                }
+                else
+                {
+                    Assert.AreEqual(rec1Val, rec2Val);
+                }
+            }
+        }
     }
+
     enum EnumType
     {
         THIRD,
@@ -260,7 +345,15 @@ namespace Avro.Test
     class EnumRecord : ISpecificRecord
     {
         public EnumType enumType { get; set; }
-        public Schema Schema { get; set; }
+        public Schema Schema
+        {
+            get
+            {
+                return Schema.Parse("{\"type\":\"record\",\"name\":\"EnumRecord\",\"namespace\":\"Avro.Test\"," + 
+                                        "\"fields\":[{\"name\":\"enumType\",\"type\": { \"type\": \"enum\", \"name\":" +
+                                        " \"EnumType\", \"symbols\": [\"THIRD\", \"FIRST\", \"SECOND\"]} }]}");
+            }
+        }
 
         public object Get(int fieldPos)
         {



Mime
View raw message