Return-Path: X-Original-To: apmail-ignite-commits-archive@minotaur.apache.org Delivered-To: apmail-ignite-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 9CDA618C47 for ; Wed, 11 Nov 2015 09:12:49 +0000 (UTC) Received: (qmail 91108 invoked by uid 500); 11 Nov 2015 09:12:49 -0000 Delivered-To: apmail-ignite-commits-archive@ignite.apache.org Received: (qmail 91020 invoked by uid 500); 11 Nov 2015 09:12:49 -0000 Mailing-List: contact commits-help@ignite.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.apache.org Delivered-To: mailing list commits@ignite.apache.org Received: (qmail 90515 invoked by uid 99); 11 Nov 2015 09:12:48 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 11 Nov 2015 09:12:48 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 83389E0593; Wed, 11 Nov 2015 09:12:48 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: vozerov@apache.org To: commits@ignite.apache.org Date: Wed, 11 Nov 2015 09:13:00 -0000 Message-Id: <34a21824375b456696b41242a2771e12@git.apache.org> In-Reply-To: <81bf422c13814119918c9c27e5d01989@git.apache.org> References: <81bf422c13814119918c9c27e5d01989@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [13/24] ignite git commit: IGNITE-1845: Adopted new binary API in .Net. http://git-wip-us.apache.org/repos/asf/ignite/blob/894057e5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamBase.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamBase.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamBase.cs new file mode 100644 index 0000000..91b8717 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamBase.cs @@ -0,0 +1,1253 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Apache.Ignite.Core.Impl.Binary.IO +{ + using System; + using System.IO; + using System.Text; + using Apache.Ignite.Core.Impl.Memory; + + /// + /// Base class for managed and unmanaged data streams. + /// + internal unsafe abstract class BinaryStreamBase : IBinaryStream + { + /** Byte: zero. */ + private const byte ByteZero = 0; + + /** Byte: one. */ + private const byte ByteOne = 1; + + /** LITTLE_ENDIAN flag. */ + private static readonly bool LittleEndian = BitConverter.IsLittleEndian; + + /** Position. */ + protected int Pos; + + /** Disposed flag. */ + private bool _disposed; + + /// + /// Write byte. + /// + /// Byte value. + public abstract void WriteByte(byte val); + + /// + /// Read byte. + /// + /// + /// Byte value. + /// + public abstract byte ReadByte(); + + /// + /// Write byte array. + /// + /// Byte array. + public abstract void WriteByteArray(byte[] val); + + /// + /// Internal routine to write byte array. + /// + /// Byte array. + /// Data pointer. + protected static void WriteByteArray0(byte[] val, byte* data) + { + fixed (byte* val0 = val) + { + CopyMemory(val0, data, val.Length); + } + } + + /// + /// Read byte array. + /// + /// Count. + /// + /// Byte array. + /// + public abstract byte[] ReadByteArray(int cnt); + + /// + /// Internal routine to read byte array. + /// + /// Array length. + /// Data pointer. + /// Byte array + protected static byte[] ReadByteArray0(int len, byte* data) + { + byte[] res = new byte[len]; + + fixed (byte* res0 = res) + { + CopyMemory(data, res0, len); + } + + return res; + } + + /// + /// Write bool. + /// + /// Bool value. + public void WriteBool(bool val) + { + WriteByte(val ? ByteOne : ByteZero); + } + + /// + /// Read bool. + /// + /// + /// Bool value. + /// + public bool ReadBool() + { + return ReadByte() == ByteOne; + } + + /// + /// Write bool array. + /// + /// Bool array. + public abstract void WriteBoolArray(bool[] val); + + /// + /// Internal routine to write bool array. + /// + /// Bool array. + /// Data pointer. + protected static void WriteBoolArray0(bool[] val, byte* data) + { + fixed (bool* val0 = val) + { + CopyMemory((byte*)val0, data, val.Length); + } + } + + /// + /// Read bool array. + /// + /// Count. + /// + /// Bool array. + /// + public abstract bool[] ReadBoolArray(int cnt); + + /// + /// Internal routine to read bool array. + /// + /// Array length. + /// Data pointer. + /// Bool array + protected static bool[] ReadBoolArray0(int len, byte* data) + { + bool[] res = new bool[len]; + + fixed (bool* res0 = res) + { + CopyMemory(data, (byte*)res0, len); + } + + return res; + } + + /// + /// Write short. + /// + /// Short value. + public abstract void WriteShort(short val); + + /// + /// Internal routine to write short value. + /// + /// Short value. + /// Data pointer. + protected static void WriteShort0(short val, byte* data) + { + if (LittleEndian) + *((short*)data) = val; + else + { + byte* valPtr = (byte*)&val; + + data[0] = valPtr[1]; + data[1] = valPtr[0]; + } + } + + /// + /// Read short. + /// + /// + /// Short value. + /// + public abstract short ReadShort(); + + /// + /// Internal routine to read short value. + /// + /// Data pointer. + /// Short value + protected static short ReadShort0(byte* data) + { + short val; + + if (LittleEndian) + val = *((short*)data); + else + { + byte* valPtr = (byte*)&val; + + valPtr[0] = data[1]; + valPtr[1] = data[0]; + } + + return val; + } + + /// + /// Write short array. + /// + /// Short array. + public abstract void WriteShortArray(short[] val); + + /// + /// Internal routine to write short array. + /// + /// Short array. + /// Data pointer. + /// Bytes count. + protected static void WriteShortArray0(short[] val, byte* data, int cnt) + { + if (LittleEndian) + { + fixed (short* val0 = val) + { + CopyMemory((byte*)val0, data, cnt); + } + } + else + { + byte* curPos = data; + + for (int i = 0; i < val.Length; i++) + { + short val0 = val[i]; + + byte* valPtr = (byte*)&(val0); + + *curPos++ = valPtr[1]; + *curPos++ = valPtr[0]; + } + } + } + + /// + /// Read short array. + /// + /// Count. + /// + /// Short array. + /// + public abstract short[] ReadShortArray(int cnt); + + /// + /// Internal routine to read short array. + /// + /// Array length. + /// Data pointer. + /// Bytes count. + /// Short array + protected static short[] ReadShortArray0(int len, byte* data, int cnt) + { + short[] res = new short[len]; + + if (LittleEndian) + { + fixed (short* res0 = res) + { + CopyMemory(data, (byte*)res0, cnt); + } + } + else + { + for (int i = 0; i < len; i++) + { + short val; + + byte* valPtr = (byte*)&val; + + valPtr[1] = *data++; + valPtr[0] = *data++; + + res[i] = val; + } + } + + return res; + } + + /// + /// Write char. + /// + /// Char value. + public void WriteChar(char val) + { + WriteShort(*(short*)(&val)); + } + + /// + /// Read char. + /// + /// + /// Char value. + /// + public char ReadChar() + { + short val = ReadShort(); + + return *(char*)(&val); + } + + /// + /// Write char array. + /// + /// Char array. + public abstract void WriteCharArray(char[] val); + + /// + /// Internal routine to write char array. + /// + /// Char array. + /// Data pointer. + /// Bytes count. + protected static void WriteCharArray0(char[] val, byte* data, int cnt) + { + if (LittleEndian) + { + fixed (char* val0 = val) + { + CopyMemory((byte*)val0, data, cnt); + } + } + else + { + byte* curPos = data; + + for (int i = 0; i < val.Length; i++) + { + char val0 = val[i]; + + byte* valPtr = (byte*)&(val0); + + *curPos++ = valPtr[1]; + *curPos++ = valPtr[0]; + } + } + } + + /// + /// Read char array. + /// + /// Count. + /// + /// Char array. + /// + public abstract char[] ReadCharArray(int cnt); + + /// + /// Internal routine to read char array. + /// + /// Count. + /// Data pointer. + /// Bytes count. + /// Char array + protected static char[] ReadCharArray0(int len, byte* data, int cnt) + { + char[] res = new char[len]; + + if (LittleEndian) + { + fixed (char* res0 = res) + { + CopyMemory(data, (byte*)res0, cnt); + } + } + else + { + for (int i = 0; i < len; i++) + { + char val; + + byte* valPtr = (byte*)&val; + + valPtr[1] = *data++; + valPtr[0] = *data++; + + res[i] = val; + } + } + + return res; + } + + /// + /// Write int. + /// + /// Int value. + public abstract void WriteInt(int val); + + /// + /// Write int to specific position. + /// + /// Position. + /// Value. + public abstract void WriteInt(int writePos, int val); + + /// + /// Internal routine to write int value. + /// + /// Int value. + /// Data pointer. + protected static void WriteInt0(int val, byte* data) + { + if (LittleEndian) + *((int*)data) = val; + else + { + byte* valPtr = (byte*)&val; + + data[0] = valPtr[3]; + data[1] = valPtr[2]; + data[2] = valPtr[1]; + data[3] = valPtr[0]; + } + } + + /// + /// Read int. + /// + /// + /// Int value. + /// + public abstract int ReadInt(); + + /// + /// Internal routine to read int value. + /// + /// Data pointer. + /// Int value + protected static int ReadInt0(byte* data) { + int val; + + if (LittleEndian) + val = *((int*)data); + else + { + byte* valPtr = (byte*)&val; + + valPtr[0] = data[3]; + valPtr[1] = data[2]; + valPtr[2] = data[1]; + valPtr[3] = data[0]; + } + + return val; + } + + /// + /// Write int array. + /// + /// Int array. + public abstract void WriteIntArray(int[] val); + + /// + /// Internal routine to write int array. + /// + /// Int array. + /// Data pointer. + /// Bytes count. + protected static void WriteIntArray0(int[] val, byte* data, int cnt) + { + if (LittleEndian) + { + fixed (int* val0 = val) + { + CopyMemory((byte*)val0, data, cnt); + } + } + else + { + byte* curPos = data; + + for (int i = 0; i < val.Length; i++) + { + int val0 = val[i]; + + byte* valPtr = (byte*)&(val0); + + *curPos++ = valPtr[3]; + *curPos++ = valPtr[2]; + *curPos++ = valPtr[1]; + *curPos++ = valPtr[0]; + } + } + } + + /// + /// Read int array. + /// + /// Count. + /// + /// Int array. + /// + public abstract int[] ReadIntArray(int cnt); + + /// + /// Internal routine to read int array. + /// + /// Count. + /// Data pointer. + /// Bytes count. + /// Int array + protected static int[] ReadIntArray0(int len, byte* data, int cnt) + { + int[] res = new int[len]; + + if (LittleEndian) + { + fixed (int* res0 = res) + { + CopyMemory(data, (byte*)res0, cnt); + } + } + else + { + for (int i = 0; i < len; i++) + { + int val; + + byte* valPtr = (byte*)&val; + + valPtr[3] = *data++; + valPtr[2] = *data++; + valPtr[1] = *data++; + valPtr[0] = *data++; + + res[i] = val; + } + } + + return res; + } + + /// + /// Write float. + /// + /// Float value. + public void WriteFloat(float val) + { + int val0 = *(int*)(&val); + + WriteInt(val0); + } + + /// + /// Read float. + /// + /// + /// Float value. + /// + public float ReadFloat() + { + int val = ReadInt(); + + return *(float*)(&val); + } + + /// + /// Write float array. + /// + /// Float array. + public abstract void WriteFloatArray(float[] val); + + /// + /// Internal routine to write float array. + /// + /// Int array. + /// Data pointer. + /// Bytes count. + protected static void WriteFloatArray0(float[] val, byte* data, int cnt) + { + if (LittleEndian) + { + fixed (float* val0 = val) + { + CopyMemory((byte*)val0, data, cnt); + } + } + else + { + byte* curPos = data; + + for (int i = 0; i < val.Length; i++) + { + float val0 = val[i]; + + byte* valPtr = (byte*)&(val0); + + *curPos++ = valPtr[3]; + *curPos++ = valPtr[2]; + *curPos++ = valPtr[1]; + *curPos++ = valPtr[0]; + } + } + } + + /// + /// Read float array. + /// + /// Count. + /// + /// Float array. + /// + public abstract float[] ReadFloatArray(int cnt); + + /// + /// Internal routine to read float array. + /// + /// Count. + /// Data pointer. + /// Bytes count. + /// Float array + protected static float[] ReadFloatArray0(int len, byte* data, int cnt) + { + float[] res = new float[len]; + + if (LittleEndian) + { + fixed (float* res0 = res) + { + CopyMemory(data, (byte*)res0, cnt); + } + } + else + { + for (int i = 0; i < len; i++) + { + int val; + + byte* valPtr = (byte*)&val; + + valPtr[3] = *data++; + valPtr[2] = *data++; + valPtr[1] = *data++; + valPtr[0] = *data++; + + res[i] = val; + } + } + + return res; + } + + /// + /// Write long. + /// + /// Long value. + public abstract void WriteLong(long val); + + /// + /// Internal routine to write long value. + /// + /// Long value. + /// Data pointer. + protected static void WriteLong0(long val, byte* data) + { + if (LittleEndian) + *((long*)data) = val; + else + { + byte* valPtr = (byte*)&val; + + data[0] = valPtr[7]; + data[1] = valPtr[6]; + data[2] = valPtr[5]; + data[3] = valPtr[4]; + data[4] = valPtr[3]; + data[5] = valPtr[2]; + data[6] = valPtr[1]; + data[7] = valPtr[0]; + } + } + + /// + /// Read long. + /// + /// + /// Long value. + /// + public abstract long ReadLong(); + + /// + /// Internal routine to read long value. + /// + /// Data pointer. + /// Long value + protected static long ReadLong0(byte* data) + { + long val; + + if (LittleEndian) + val = *((long*)data); + else + { + byte* valPtr = (byte*)&val; + + valPtr[0] = data[7]; + valPtr[1] = data[6]; + valPtr[2] = data[5]; + valPtr[3] = data[4]; + valPtr[4] = data[3]; + valPtr[5] = data[2]; + valPtr[6] = data[1]; + valPtr[7] = data[0]; + } + + return val; + } + + /// + /// Write long array. + /// + /// Long array. + public abstract void WriteLongArray(long[] val); + + /// + /// Internal routine to write long array. + /// + /// Long array. + /// Data pointer. + /// Bytes count. + protected static void WriteLongArray0(long[] val, byte* data, int cnt) + { + if (LittleEndian) + { + fixed (long* val0 = val) + { + CopyMemory((byte*)val0, data, cnt); + } + } + else + { + byte* curPos = data; + + for (int i = 0; i < val.Length; i++) + { + long val0 = val[i]; + + byte* valPtr = (byte*)&(val0); + + *curPos++ = valPtr[7]; + *curPos++ = valPtr[6]; + *curPos++ = valPtr[5]; + *curPos++ = valPtr[4]; + *curPos++ = valPtr[3]; + *curPos++ = valPtr[2]; + *curPos++ = valPtr[1]; + *curPos++ = valPtr[0]; + } + } + } + + /// + /// Read long array. + /// + /// Count. + /// + /// Long array. + /// + public abstract long[] ReadLongArray(int cnt); + + /// + /// Internal routine to read long array. + /// + /// Count. + /// Data pointer. + /// Bytes count. + /// Long array + protected static long[] ReadLongArray0(int len, byte* data, int cnt) + { + long[] res = new long[len]; + + if (LittleEndian) + { + fixed (long* res0 = res) + { + CopyMemory(data, (byte*)res0, cnt); + } + } + else + { + for (int i = 0; i < len; i++) + { + long val; + + byte* valPtr = (byte*)&val; + + valPtr[7] = *data++; + valPtr[6] = *data++; + valPtr[5] = *data++; + valPtr[4] = *data++; + valPtr[3] = *data++; + valPtr[2] = *data++; + valPtr[1] = *data++; + valPtr[0] = *data++; + + res[i] = val; + } + } + + return res; + } + + /// + /// Write double. + /// + /// Double value. + public void WriteDouble(double val) + { + long val0 = *(long*)(&val); + + WriteLong(val0); + } + + /// + /// Read double. + /// + /// + /// Double value. + /// + public double ReadDouble() + { + long val = ReadLong(); + + return *(double*)(&val); + } + + /// + /// Write double array. + /// + /// Double array. + public abstract void WriteDoubleArray(double[] val); + + /// + /// Internal routine to write double array. + /// + /// Double array. + /// Data pointer. + /// Bytes count. + protected static void WriteDoubleArray0(double[] val, byte* data, int cnt) + { + if (LittleEndian) + { + fixed (double* val0 = val) + { + CopyMemory((byte*)val0, data, cnt); + } + } + else + { + byte* curPos = data; + + for (int i = 0; i < val.Length; i++) + { + double val0 = val[i]; + + byte* valPtr = (byte*)&(val0); + + *curPos++ = valPtr[7]; + *curPos++ = valPtr[6]; + *curPos++ = valPtr[5]; + *curPos++ = valPtr[4]; + *curPos++ = valPtr[3]; + *curPos++ = valPtr[2]; + *curPos++ = valPtr[1]; + *curPos++ = valPtr[0]; + } + } + } + + /// + /// Read double array. + /// + /// Count. + /// + /// Double array. + /// + public abstract double[] ReadDoubleArray(int cnt); + + /// + /// Internal routine to read double array. + /// + /// Count. + /// Data pointer. + /// Bytes count. + /// Double array + protected static double[] ReadDoubleArray0(int len, byte* data, int cnt) + { + double[] res = new double[len]; + + if (LittleEndian) + { + fixed (double* res0 = res) + { + CopyMemory(data, (byte*)res0, cnt); + } + } + else + { + for (int i = 0; i < len; i++) + { + double val; + + byte* valPtr = (byte*)&val; + + valPtr[7] = *data++; + valPtr[6] = *data++; + valPtr[5] = *data++; + valPtr[4] = *data++; + valPtr[3] = *data++; + valPtr[2] = *data++; + valPtr[1] = *data++; + valPtr[0] = *data++; + + res[i] = val; + } + } + + return res; + } + + /// + /// Write string. + /// + /// Characters. + /// Char count. + /// Byte count. + /// Encoding. + /// + /// Amounts of bytes written. + /// + public abstract int WriteString(char* chars, int charCnt, int byteCnt, Encoding encoding); + + /// + /// Internal string write routine. + /// + /// Chars. + /// Chars count. + /// Bytes count. + /// Encoding. + /// Data. + /// Amount of bytes written. + protected static int WriteString0(char* chars, int charCnt, int byteCnt, Encoding enc, byte* data) + { + return enc.GetBytes(chars, charCnt, data, byteCnt); + } + + /// + /// Write arbitrary data. + /// + /// Source array. + /// Offset + /// Count. + public void Write(byte[] src, int off, int cnt) + { + fixed (byte* src0 = src) + { + Write(src0 + off, cnt); + } + } + + /// + /// Read arbitrary data. + /// + /// Destination array. + /// Offset. + /// Count. + /// + /// Amount of bytes read. + /// + public void Read(byte[] dest, int off, int cnt) + { + fixed (byte* dest0 = dest) + { + Read(dest0 + off, cnt); + } + } + + /// + /// Write arbitrary data. + /// + /// Source. + /// Count. + public abstract void Write(byte* src, int cnt); + + /// + /// Internal write routine. + /// + /// Source. + /// Count. + /// Data (dsetination). + protected void WriteInternal(byte* src, int cnt, byte* data) + { + CopyMemory(src, data + Pos, cnt); + } + + /// + /// Read arbitrary data. + /// + /// Destination. + /// Count. + /// + public abstract void Read(byte* dest, int cnt); + + /// + /// Internal read routine. + /// + /// Source + /// Destination. + /// Count. + /// Amount of bytes written. + protected void ReadInternal(byte* src, byte* dest, int cnt) + { + int cnt0 = Math.Min(Remaining, cnt); + + CopyMemory(src + Pos, dest, cnt0); + + ShiftRead(cnt0); + } + + /// + /// Position. + /// + public int Position + { + get { return Pos; } + } + + /// + /// Gets remaining bytes in the stream. + /// + /// + /// Remaining bytes. + /// + public abstract int Remaining { get; } + + /// + /// Gets underlying array, avoiding copying if possible. + /// + /// + /// Underlying array. + /// + public abstract byte[] GetArray(); + + /// + /// Gets underlying data in a new array. + /// + /// + /// New array with data. + /// + public abstract byte[] GetArrayCopy(); + + /// + /// Check whether array passed as argument is the same as the stream hosts. + /// + /// Array. + /// + /// True if they are same. + /// + public virtual bool IsSameArray(byte[] arr) + { + return false; + } + + /// + /// Seek to the given positoin. + /// + /// Offset. + /// Seek origin. + /// + /// Position. + /// + /// + /// Unsupported seek origin: + origin + /// or + /// Seek before origin: + newPos + /// + public int Seek(int offset, SeekOrigin origin) + { + int newPos; + + switch (origin) + { + case SeekOrigin.Begin: + { + newPos = offset; + + break; + } + + case SeekOrigin.Current: + { + newPos = Pos + offset; + + break; + } + + default: + throw new ArgumentException("Unsupported seek origin: " + origin); + } + + if (newPos < 0) + throw new ArgumentException("Seek before origin: " + newPos); + + EnsureWriteCapacity(newPos); + + Pos = newPos; + + return Pos; + } + + /** */ + public void Dispose() + { + if (_disposed) + return; + + Dispose(true); + + GC.SuppressFinalize(this); + + _disposed = true; + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + protected abstract void Dispose(bool disposing); + + /// + /// Ensure capacity for write. + /// + /// Bytes count. + protected abstract void EnsureWriteCapacity(int cnt); + + /// + /// Ensure capacity for write and shift position. + /// + /// Bytes count. + /// Position before shift. + protected int EnsureWriteCapacityAndShift(int cnt) + { + int pos0 = Pos; + + EnsureWriteCapacity(Pos + cnt); + + ShiftWrite(cnt); + + return pos0; + } + + /// + /// Ensure capacity for read. + /// + /// Bytes count. + protected abstract void EnsureReadCapacity(int cnt); + + /// + /// Ensure capacity for read and shift position. + /// + /// Bytes count. + /// Position before shift. + protected int EnsureReadCapacityAndShift(int cnt) + { + int pos0 = Pos; + + EnsureReadCapacity(cnt); + + ShiftRead(cnt); + + return pos0; + } + + /// + /// Shift position due to write + /// + /// Bytes count. + protected void ShiftWrite(int cnt) + { + Pos += cnt; + } + + /// + /// Shift position due to read. + /// + /// Bytes count. + private void ShiftRead(int cnt) + { + Pos += cnt; + } + + /// + /// Calculate new capacity. + /// + /// Current capacity. + /// Required capacity. + /// New capacity. + protected static int Capacity(int curCap, int reqCap) + { + int newCap; + + if (reqCap < 256) + newCap = 256; + else + { + newCap = curCap << 1; + + if (newCap < reqCap) + newCap = reqCap; + } + + return newCap; + } + + /// + /// Unsafe memory copy routine. + /// + /// Source. + /// Destination. + /// Length. + private static void CopyMemory(byte* src, byte* dest, int len) + { + PlatformMemoryUtils.CopyMemory(src, dest, len); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/894057e5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs new file mode 100644 index 0000000..d530713 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs @@ -0,0 +1,322 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +namespace Apache.Ignite.Core.Impl.Binary.IO +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Text; + + /// + /// Stream capable of working with binary objects. + /// + [CLSCompliant(false)] + [SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] + public unsafe interface IBinaryStream : IDisposable + { + /// + /// Write bool. + /// + /// Bool value. + void WriteBool(bool val); + + /// + /// Read bool. + /// + /// Bool value. + bool ReadBool(); + + /// + /// Write bool array. + /// + /// Bool array. + void WriteBoolArray(bool[] val); + + /// + /// Read bool array. + /// + /// Count. + /// Bool array. + bool[] ReadBoolArray(int cnt); + + /// + /// Write byte. + /// + /// Byte value. + void WriteByte(byte val); + + /// + /// Read byte. + /// + /// Byte value. + byte ReadByte(); + + /// + /// Write byte array. + /// + /// Byte array. + void WriteByteArray(byte[] val); + + /// + /// Read byte array. + /// + /// Count. + /// Byte array. + byte[] ReadByteArray(int cnt); + + /// + /// Write short. + /// + /// Short value. + void WriteShort(short val); + + /// + /// Read short. + /// + /// Short value. + short ReadShort(); + + /// + /// Write short array. + /// + /// Short array. + void WriteShortArray(short[] val); + + /// + /// Read short array. + /// + /// Count. + /// Short array. + short[] ReadShortArray(int cnt); + + /// + /// Write char. + /// + /// Char value. + void WriteChar(char val); + + /// + /// Read char. + /// + /// Char value. + char ReadChar(); + + /// + /// Write char array. + /// + /// Char array. + void WriteCharArray(char[] val); + + /// + /// Read char array. + /// + /// Count. + /// Char array. + char[] ReadCharArray(int cnt); + + /// + /// Write int. + /// + /// Int value. + void WriteInt(int val); + + /// + /// Write int to specific position. + /// + /// Position. + /// Value. + void WriteInt(int writePos, int val); + + /// + /// Read int. + /// + /// Int value. + int ReadInt(); + + /// + /// Write int array. + /// + /// Int array. + void WriteIntArray(int[] val); + + /// + /// Read int array. + /// + /// Count. + /// Int array. + int[] ReadIntArray(int cnt); + + /// + /// Write long. + /// + /// Long value. + void WriteLong(long val); + + /// + /// Read long. + /// + /// Long value. + long ReadLong(); + + /// + /// Write long array. + /// + /// Long array. + void WriteLongArray(long[] val); + + /// + /// Read long array. + /// + /// Count. + /// Long array. + long[] ReadLongArray(int cnt); + + /// + /// Write float. + /// + /// Float value. + void WriteFloat(float val); + + /// + /// Read float. + /// + /// Float value. + float ReadFloat(); + + /// + /// Write float array. + /// + /// Float array. + void WriteFloatArray(float[] val); + + /// + /// Read float array. + /// + /// Count. + /// Float array. + float[] ReadFloatArray(int cnt); + + /// + /// Write double. + /// + /// Double value. + void WriteDouble(double val); + + /// + /// Read double. + /// + /// Double value. + double ReadDouble(); + + /// + /// Write double array. + /// + /// Double array. + void WriteDoubleArray(double[] val); + + /// + /// Read double array. + /// + /// Count. + /// Double array. + double[] ReadDoubleArray(int cnt); + + /// + /// Write string. + /// + /// Characters. + /// Char count. + /// Byte count. + /// Encoding. + /// Amounts of bytes written. + int WriteString(char* chars, int charCnt, int byteCnt, Encoding encoding); + + /// + /// Write arbitrary data. + /// + /// Source array. + /// Offset + /// Count. + void Write(byte[] src, int off, int cnt); + + /// + /// Read arbitrary data. + /// + /// Destination array. + /// Offset. + /// Count. + /// Amount of bytes read. + void Read(byte[] dest, int off, int cnt); + + /// + /// Write arbitrary data. + /// + /// Source. + /// Count. + void Write(byte* src, int cnt); + + /// + /// Read arbitrary data. + /// + /// Destination. + /// Count. + void Read(byte* dest, int cnt); + + /// + /// Position. + /// + int Position + { + get; + } + + /// + /// Gets remaining bytes in the stream. + /// + /// Remaining bytes. + int Remaining { get; } + + /// + /// Gets underlying array, avoiding copying if possible. + /// + /// Underlying array. + byte[] GetArray(); + + /// + /// Gets underlying data in a new array. + /// + /// New array with data. + byte[] GetArrayCopy(); + + /// + /// Check whether array passed as argument is the same as the stream hosts. + /// + /// Array. + /// True if they are same. + bool IsSameArray(byte[] arr); + + /// + /// Seek to the given positoin. + /// + /// Offset. + /// Seek origin. + /// Position. + int Seek(int offset, SeekOrigin origin); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/894057e5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs new file mode 100644 index 0000000..251610e --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs @@ -0,0 +1,537 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Apache.Ignite.Core.Impl.Binary +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Impl.Binary.IO; + using Apache.Ignite.Core.Impl.Binary.Metadata; + using Apache.Ignite.Core.Impl.Cache; + using Apache.Ignite.Core.Impl.Cache.Query.Continuous; + using Apache.Ignite.Core.Impl.Compute; + using Apache.Ignite.Core.Impl.Compute.Closure; + using Apache.Ignite.Core.Impl.Datastream; + using Apache.Ignite.Core.Impl.Messaging; + + /// + /// Marshaller implementation. + /// + internal class Marshaller + { + /** Binary configuration. */ + private readonly BinaryConfiguration _cfg; + + /** Type to descriptor map. */ + private readonly IDictionary _typeToDesc = + new Dictionary(); + + /** Type name to descriptor map. */ + private readonly IDictionary _typeNameToDesc = + new Dictionary(); + + /** ID to descriptor map. */ + private readonly IDictionary _idToDesc = + new Dictionary(); + + /** Cached metadatas. */ + private volatile IDictionary _metas = + new Dictionary(); + + /// + /// Constructor. + /// + /// Configurtaion. + public Marshaller(BinaryConfiguration cfg) + { + // Validation. + if (cfg == null) + cfg = new BinaryConfiguration(); + + if (cfg.TypeConfigurations == null) + cfg.TypeConfigurations = new List(); + + foreach (BinaryTypeConfiguration typeCfg in cfg.TypeConfigurations) + { + if (string.IsNullOrEmpty(typeCfg.TypeName)) + throw new BinaryObjectException("Type name cannot be null or empty: " + typeCfg); + } + + // Define system types. They use internal reflective stuff, so configuration doesn't affect them. + AddSystemTypes(); + + // 2. Define user types. + var dfltSerializer = cfg.DefaultSerializer == null ? new BinaryReflectiveSerializer() : null; + + var typeResolver = new TypeResolver(); + + ICollection typeCfgs = cfg.TypeConfigurations; + + if (typeCfgs != null) + foreach (BinaryTypeConfiguration typeCfg in typeCfgs) + AddUserType(cfg, typeCfg, typeResolver, dfltSerializer); + + ICollection types = cfg.Types; + + if (types != null) + foreach (string type in types) + AddUserType(cfg, new BinaryTypeConfiguration(type), typeResolver, dfltSerializer); + + if (cfg.DefaultSerializer == null) + cfg.DefaultSerializer = dfltSerializer; + + _cfg = cfg; + } + + /// + /// Gets or sets the backing grid. + /// + public Ignite Ignite { get; set; } + + /// + /// Marshal object. + /// + /// Value. + /// Serialized data as byte array. + public byte[] Marshal(T val) + { + BinaryHeapStream stream = new BinaryHeapStream(128); + + Marshal(val, stream); + + return stream.GetArrayCopy(); + } + + /// + /// Marshal object. + /// + /// Value. + /// Output stream. + /// Collection of metadatas (if any). + private void Marshal(T val, IBinaryStream stream) + { + BinaryWriter writer = StartMarshal(stream); + + writer.Write(val); + + FinishMarshal(writer); + } + + /// + /// Start marshal session. + /// + /// Stream. + /// Writer. + public BinaryWriter StartMarshal(IBinaryStream stream) + { + return new BinaryWriter(this, stream); + } + + /// + /// Finish marshal session. + /// + /// Writer. + /// Dictionary with metadata. + public void FinishMarshal(IBinaryWriter writer) + { + var meta = ((BinaryWriter) writer).GetBinaryTypes(); + + var ignite = Ignite; + + if (ignite != null && meta != null && meta.Count > 0) + ignite.PutBinaryTypes(meta); + } + + /// + /// Unmarshal object. + /// + /// + /// Data array. + /// Whether to keep binarizable as binary. + /// + /// Object. + /// + public T Unmarshal(byte[] data, bool keepBinary) + { + return Unmarshal(new BinaryHeapStream(data), keepBinary); + } + + /// + /// Unmarshal object. + /// + /// Data array. + /// The mode. + /// + /// Object. + /// + public T Unmarshal(byte[] data, BinaryMode mode = BinaryMode.Deserialize) + { + return Unmarshal(new BinaryHeapStream(data), mode); + } + + /// + /// Unmarshal object. + /// + /// Stream over underlying byte array with correct position. + /// Whether to keep binary objects in binary form. + /// + /// Object. + /// + public T Unmarshal(IBinaryStream stream, bool keepBinary) + { + return Unmarshal(stream, keepBinary ? BinaryMode.KeepBinary : BinaryMode.Deserialize, null); + } + + /// + /// Unmarshal object. + /// + /// Stream over underlying byte array with correct position. + /// The mode. + /// + /// Object. + /// + public T Unmarshal(IBinaryStream stream, BinaryMode mode = BinaryMode.Deserialize) + { + return Unmarshal(stream, mode, null); + } + + /// + /// Unmarshal object. + /// + /// Stream over underlying byte array with correct position. + /// The mode. + /// Builder. + /// + /// Object. + /// + public T Unmarshal(IBinaryStream stream, BinaryMode mode, BinaryObjectBuilder builder) + { + return new BinaryReader(this, _idToDesc, stream, mode, builder).Deserialize(); + } + + /// + /// Start unmarshal session. + /// + /// Stream. + /// Whether to keep binarizable as binary. + /// + /// Reader. + /// + public BinaryReader StartUnmarshal(IBinaryStream stream, bool keepBinary) + { + return new BinaryReader(this, _idToDesc, stream, + keepBinary ? BinaryMode.KeepBinary : BinaryMode.Deserialize, null); + } + + /// + /// Start unmarshal session. + /// + /// Stream. + /// The mode. + /// Reader. + public BinaryReader StartUnmarshal(IBinaryStream stream, BinaryMode mode = BinaryMode.Deserialize) + { + return new BinaryReader(this, _idToDesc, stream, mode, null); + } + + /// + /// Gets metadata for the given type ID. + /// + /// Type ID. + /// Metadata or null. + public IBinaryType GetBinaryType(int typeId) + { + if (Ignite != null) + { + IBinaryType meta = Ignite.GetBinaryType(typeId); + + if (meta != null) + return meta; + } + + return BinaryType.EmptyMeta; + } + + /// + /// Gets binary type handler for the given type ID. + /// + /// Type descriptor. + /// Binary type handler. + public IBinaryTypeHandler GetBinaryTypeHandler(IBinaryTypeDescriptor desc) + { + BinaryTypeHolder holder; + + if (!_metas.TryGetValue(desc.TypeId, out holder)) + { + lock (this) + { + if (!_metas.TryGetValue(desc.TypeId, out holder)) + { + IDictionary metas0 = + new Dictionary(_metas); + + holder = new BinaryTypeHolder(desc.TypeId, desc.TypeName, desc.AffinityKeyFieldName); + + metas0[desc.TypeId] = holder; + + _metas = metas0; + } + } + } + + if (holder != null) + { + ICollection ids = holder.FieldIds(); + + bool newType = ids.Count == 0 && !holder.Saved(); + + return new BinaryTypeHashsetHandler(ids, newType); + } + + return null; + } + + /// + /// Callback invoked when metadata has been sent to the server and acknowledged by it. + /// + /// Binary types. + public void OnBinaryTypesSent(IDictionary newMetas) + { + foreach (KeyValuePair metaEntry in newMetas) + { + BinaryType meta = (BinaryType) metaEntry.Value; + + IDictionary> mergeInfo = + new Dictionary>(meta.FieldsMap().Count); + + foreach (KeyValuePair fieldMeta in meta.FieldsMap()) + { + int fieldId = BinaryUtils.FieldId(metaEntry.Key, fieldMeta.Key, null, null); + + mergeInfo[fieldId] = new Tuple(fieldMeta.Key, fieldMeta.Value); + } + + _metas[metaEntry.Key].Merge(mergeInfo); + } + } + + /// + /// Gets descriptor for type. + /// + /// Type. + /// Descriptor. + public IBinaryTypeDescriptor GetDescriptor(Type type) + { + IBinaryTypeDescriptor desc; + + _typeToDesc.TryGetValue(type, out desc); + + return desc; + } + + /// + /// Gets descriptor for type name. + /// + /// Type name. + /// Descriptor. + public IBinaryTypeDescriptor GetDescriptor(string typeName) + { + IBinaryTypeDescriptor desc; + + return _typeNameToDesc.TryGetValue(typeName, out desc) ? desc : + new BinarySurrogateTypeDescriptor(_cfg, typeName); + } + + /// + /// + /// + /// + /// + /// + public IBinaryTypeDescriptor GetDescriptor(bool userType, int typeId) + { + IBinaryTypeDescriptor desc; + + return _idToDesc.TryGetValue(BinaryUtils.TypeKey(userType, typeId), out desc) ? desc : + userType ? new BinarySurrogateTypeDescriptor(_cfg, typeId) : null; + } + + /// + /// Add user type. + /// + /// Configuration. + /// Type configuration. + /// The type resolver. + /// The default serializer. + private void AddUserType(BinaryConfiguration cfg, BinaryTypeConfiguration typeCfg, + TypeResolver typeResolver, IBinarySerializer dfltSerializer) + { + // Get converter/mapper/serializer. + IBinaryNameMapper nameMapper = typeCfg.NameMapper ?? cfg.DefaultNameMapper; + + IBinaryIdMapper idMapper = typeCfg.IdMapper ?? cfg.DefaultIdMapper; + + bool keepDeserialized = typeCfg.KeepDeserialized ?? cfg.DefaultKeepDeserialized; + + // Try resolving type. + Type type = typeResolver.ResolveType(typeCfg.TypeName); + + if (type != null) + { + // Type is found. + var typeName = GetTypeName(type); + + int typeId = BinaryUtils.TypeId(typeName, nameMapper, idMapper); + + var serializer = typeCfg.Serializer ?? cfg.DefaultSerializer + ?? GetBinarizableSerializer(type) ?? dfltSerializer; + + var refSerializer = serializer as BinaryReflectiveSerializer; + + if (refSerializer != null) + refSerializer.Register(type, typeId, nameMapper, idMapper); + + AddType(type, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, serializer, + typeCfg.AffinityKeyFieldName); + } + else + { + // Type is not found. + string typeName = BinaryUtils.SimpleTypeName(typeCfg.TypeName); + + int typeId = BinaryUtils.TypeId(typeName, nameMapper, idMapper); + + AddType(null, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, null, + typeCfg.AffinityKeyFieldName); + } + } + + /// + /// Gets the for a type if it is compatible. + /// + /// The type. + /// Resulting , or null. + private static IBinarySerializer GetBinarizableSerializer(Type type) + { + return type.GetInterfaces().Contains(typeof (IBinarizable)) + ? BinarizableSerializer.Instance + : null; + } + + /// + /// Add type. + /// + /// Type. + /// Type ID. + /// Type name. + /// User type flag. + /// Whether to cache deserialized value in IBinaryObject + /// Name mapper. + /// ID mapper. + /// Serializer. + /// Affinity key field name. + private void AddType(Type type, int typeId, string typeName, bool userType, + bool keepDeserialized, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper, + IBinarySerializer serializer, string affKeyFieldName) + { + long typeKey = BinaryUtils.TypeKey(userType, typeId); + + IBinaryTypeDescriptor conflictingType; + + if (_idToDesc.TryGetValue(typeKey, out conflictingType)) + { + var type1 = conflictingType.Type != null + ? conflictingType.Type.AssemblyQualifiedName + : conflictingType.TypeName; + + var type2 = type != null ? type.AssemblyQualifiedName : typeName; + + throw new BinaryObjectException(string.Format("Conflicting type IDs [type1='{0}', " + + "type2='{1}', typeId={2}]", type1, type2, typeId)); + } + + if (userType && _typeNameToDesc.ContainsKey(typeName)) + throw new BinaryObjectException("Conflicting type name: " + typeName); + + IBinaryTypeDescriptor descriptor = + new BinaryFullTypeDescriptor(type, typeId, typeName, userType, nameMapper, idMapper, serializer, + keepDeserialized, affKeyFieldName); + + if (type != null) + _typeToDesc[type] = descriptor; + + if (userType) + _typeNameToDesc[typeName] = descriptor; + + _idToDesc[typeKey] = descriptor; + } + + /// + /// Adds a predefined system type. + /// + private void AddSystemType(byte typeId, Func ctor) where T : IBinaryWriteAware + { + var type = typeof(T); + + var serializer = new BinarySystemTypeSerializer(ctor); + + AddType(type, typeId, GetTypeName(type), false, false, null, null, serializer, null); + } + + /// + /// Adds predefined system types. + /// + private void AddSystemTypes() + { + AddSystemType(BinaryUtils.TypeNativeJobHolder, w => new ComputeJobHolder(w)); + AddSystemType(BinaryUtils.TypeComputeJobWrapper, w => new ComputeJobWrapper(w)); + AddSystemType(BinaryUtils.TypeIgniteProxy, w => new IgniteProxy()); + AddSystemType(BinaryUtils.TypeComputeOutFuncJob, w => new ComputeOutFuncJob(w)); + AddSystemType(BinaryUtils.TypeComputeOutFuncWrapper, w => new ComputeOutFuncWrapper(w)); + AddSystemType(BinaryUtils.TypeComputeFuncWrapper, w => new ComputeFuncWrapper(w)); + AddSystemType(BinaryUtils.TypeComputeFuncJob, w => new ComputeFuncJob(w)); + AddSystemType(BinaryUtils.TypeComputeActionJob, w => new ComputeActionJob(w)); + AddSystemType(BinaryUtils.TypeContinuousQueryRemoteFilterHolder, w => new ContinuousQueryFilterHolder(w)); + AddSystemType(BinaryUtils.TypeSerializableHolder, w => new SerializableObjectHolder(w)); + AddSystemType(BinaryUtils.TypeDateTimeHolder, w => new DateTimeHolder(w)); + AddSystemType(BinaryUtils.TypeCacheEntryProcessorHolder, w => new CacheEntryProcessorHolder(w)); + AddSystemType(BinaryUtils.TypeCacheEntryPredicateHolder, w => new CacheEntryFilterHolder(w)); + AddSystemType(BinaryUtils.TypeMessageListenerHolder, w => new MessageListenerHolder(w)); + AddSystemType(BinaryUtils.TypeStreamReceiverHolder, w => new StreamReceiverHolder(w)); + } + + /// + /// Gets the name of the type. + /// + /// The type. + /// + /// Simple type name for non-generic types; simple type name with appended generic arguments for generic types. + /// + private static string GetTypeName(Type type) + { + if (!type.IsGenericType) + return type.Name; + + var args = type.GetGenericArguments().Select(GetTypeName).Aggregate((x, y) => x + "," + y); + + return string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", type.Name, args); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/894057e5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryType.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryType.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryType.cs new file mode 100644 index 0000000..3e9a28d --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryType.cs @@ -0,0 +1,200 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Apache.Ignite.Core.Impl.Binary.Metadata +{ + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using Apache.Ignite.Core.Binary; + + /// + /// Binary metadata implementation. + /// + internal class BinaryType : IBinaryType + { + /** Empty metadata. */ + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly BinaryType EmptyMeta = + new BinaryType(BinaryUtils.TypeObject, BinaryTypeNames.TypeNameObject, null, null); + + /** Empty dictionary. */ + private static readonly IDictionary EmptyDict = new Dictionary(); + + /** Empty list. */ + private static readonly ICollection EmptyList = new List().AsReadOnly(); + + /** Fields. */ + private readonly IDictionary _fields; + + /// + /// Get type name by type ID. + /// + /// Type ID. + /// Type name. + private static string ConvertTypeName(int typeId) + { + switch (typeId) + { + case BinaryUtils.TypeBool: + return BinaryTypeNames.TypeNameBool; + case BinaryUtils.TypeByte: + return BinaryTypeNames.TypeNameByte; + case BinaryUtils.TypeShort: + return BinaryTypeNames.TypeNameShort; + case BinaryUtils.TypeChar: + return BinaryTypeNames.TypeNameChar; + case BinaryUtils.TypeInt: + return BinaryTypeNames.TypeNameInt; + case BinaryUtils.TypeLong: + return BinaryTypeNames.TypeNameLong; + case BinaryUtils.TypeFloat: + return BinaryTypeNames.TypeNameFloat; + case BinaryUtils.TypeDouble: + return BinaryTypeNames.TypeNameDouble; + case BinaryUtils.TypeDecimal: + return BinaryTypeNames.TypeNameDecimal; + case BinaryUtils.TypeString: + return BinaryTypeNames.TypeNameString; + case BinaryUtils.TypeGuid: + return BinaryTypeNames.TypeNameGuid; + case BinaryUtils.TypeTimestamp: + return BinaryTypeNames.TypeNameTimestamp; + case BinaryUtils.TypeEnum: + return BinaryTypeNames.TypeNameEnum; + case BinaryUtils.TypeBinary: + case BinaryUtils.TypeObject: + return BinaryTypeNames.TypeNameObject; + case BinaryUtils.TypeArrayBool: + return BinaryTypeNames.TypeNameArrayBool; + case BinaryUtils.TypeArrayByte: + return BinaryTypeNames.TypeNameArrayByte; + case BinaryUtils.TypeArrayShort: + return BinaryTypeNames.TypeNameArrayShort; + case BinaryUtils.TypeArrayChar: + return BinaryTypeNames.TypeNameArrayChar; + case BinaryUtils.TypeArrayInt: + return BinaryTypeNames.TypeNameArrayInt; + case BinaryUtils.TypeArrayLong: + return BinaryTypeNames.TypeNameArrayLong; + case BinaryUtils.TypeArrayFloat: + return BinaryTypeNames.TypeNameArrayFloat; + case BinaryUtils.TypeArrayDouble: + return BinaryTypeNames.TypeNameArrayDouble; + case BinaryUtils.TypeArrayDecimal: + return BinaryTypeNames.TypeNameArrayDecimal; + case BinaryUtils.TypeArrayString: + return BinaryTypeNames.TypeNameArrayString; + case BinaryUtils.TypeArrayGuid: + return BinaryTypeNames.TypeNameArrayGuid; + case BinaryUtils.TypeArrayTimestamp: + return BinaryTypeNames.TypeNameArrayTimestamp; + case BinaryUtils.TypeArrayEnum: + return BinaryTypeNames.TypeNameArrayEnum; + case BinaryUtils.TypeArray: + return BinaryTypeNames.TypeNameArrayObject; + case BinaryUtils.TypeCollection: + return BinaryTypeNames.TypeNameCollection; + case BinaryUtils.TypeDictionary: + return BinaryTypeNames.TypeNameMap; + default: + throw new BinaryObjectException("Invalid type ID: " + typeId); + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The reader. + public BinaryType(IBinaryRawReader reader) + { + TypeId = reader.ReadInt(); + TypeName = reader.ReadString(); + AffinityKeyFieldName = reader.ReadString(); + _fields = reader.ReadDictionaryAsGeneric(); + } + + /// + /// Constructor. + /// + /// Type ID. + /// Type name. + /// Fields. + /// Affinity key field name. + public BinaryType(int typeId, string typeName, IDictionary fields, + string affKeyFieldName) + { + TypeId = typeId; + TypeName = typeName; + AffinityKeyFieldName = affKeyFieldName; + _fields = fields; + } + + /// + /// Type ID. + /// + /// + public int TypeId { get; private set; } + + /// + /// Gets type name. + /// + public string TypeName { get; private set; } + + /// + /// Gets field names for that type. + /// + public ICollection Fields + { + get { return _fields != null ? _fields.Keys : EmptyList; } + } + + /// + /// Gets field type for the given field name. + /// + /// Field name. + /// + /// Field type. + /// + public string GetFieldTypeName(string fieldName) + { + if (_fields != null) + { + int typeId; + + _fields.TryGetValue(fieldName, out typeId); + + return ConvertTypeName(typeId); + } + + return null; + } + + /// + /// Gets optional affinity key field name. + /// + public string AffinityKeyFieldName { get; private set; } + + /// + /// Gets fields map. + /// + /// Fields map. + public IDictionary FieldsMap() + { + return _fields ?? EmptyDict; + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/894057e5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHashsetHandler.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHashsetHandler.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHashsetHandler.cs new file mode 100644 index 0000000..af5902f --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHashsetHandler.cs @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Apache.Ignite.Core.Impl.Binary.Metadata +{ + using System.Collections.Generic; + + /// + /// Metadata handler which uses hash set to determine whether field was already written or not. + /// + internal class BinaryTypeHashsetHandler : IBinaryTypeHandler + { + /** Empty fields collection. */ + private static readonly IDictionary EmptyFields = new Dictionary(); + + /** IDs known when serialization starts. */ + private readonly ICollection _ids; + + /** New fields. */ + private IDictionary _fieldMap; + + /** */ + private readonly bool _newType; + + /// + /// Constructor. + /// + /// IDs. + /// True is metadata for type is not saved. + public BinaryTypeHashsetHandler(ICollection ids, bool newType) + { + _ids = ids; + _newType = newType; + } + + /** */ + public void OnFieldWrite(int fieldId, string fieldName, int typeId) + { + if (!_ids.Contains(fieldId)) + { + if (_fieldMap == null) + _fieldMap = new Dictionary(); + + if (!_fieldMap.ContainsKey(fieldName)) + _fieldMap[fieldName] = typeId; + } + } + + /** */ + public IDictionary OnObjectWriteFinished() + { + return _fieldMap ?? (_newType ? EmptyFields : null); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/894057e5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHolder.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHolder.cs new file mode 100644 index 0000000..524cda9 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHolder.cs @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Apache.Ignite.Core.Impl.Binary.Metadata +{ + using System; + using System.Collections.Generic; + using Apache.Ignite.Core.Binary; + + /// + /// Metadata for particular type. + /// + internal class BinaryTypeHolder + { + /** Type ID. */ + private readonly int _typeId; + + /** Type name. */ + private readonly string _typeName; + + /** Affinity key field name. */ + private readonly string _affKeyFieldName; + + /** Empty metadata when nothig is know about object fields yet. */ + private readonly IBinaryType _emptyMeta; + + /** Collection of know field IDs. */ + private volatile ICollection _ids; + + /** Last known unmodifiable metadata which is given to the user. */ + private volatile BinaryType _meta; + + /** Saved flag (set if type metadata was saved at least once). */ + private volatile bool _saved; + + /// + /// Constructor. + /// + /// Type ID. + /// Type name. + /// Affinity key field name. + public BinaryTypeHolder(int typeId, string typeName, string affKeyFieldName) + { + _typeId = typeId; + _typeName = typeName; + _affKeyFieldName = affKeyFieldName; + + _emptyMeta = new BinaryType(typeId, typeName, null, affKeyFieldName); + } + + /// + /// Get saved flag. + /// + /// True if type metadata was saved at least once. + public bool Saved() + { + return _saved; + } + + /// + /// Get current type metadata. + /// + /// Type metadata. + public IBinaryType BinaryType + { + get { return _meta ?? _emptyMeta; } + } + + /// + /// Currently cached field IDs. + /// + /// Cached field IDs. + public ICollection FieldIds() + { + ICollection ids0 = _ids; + + if (_ids == null) + { + lock (this) + { + ids0 = _ids; + + if (ids0 == null) + { + ids0 = new HashSet(); + + _ids = ids0; + } + } + } + + return ids0; + } + + /// + /// Merge newly sent field metadatas into existing ones. + /// + /// New field metadatas map. + public void Merge(IDictionary> newMap) + { + _saved = true; + + if (newMap == null || newMap.Count == 0) + return; + + lock (this) + { + // 1. Create copies of the old meta. + ICollection ids0 = _ids; + BinaryType meta0 = _meta; + + ICollection newIds = ids0 != null ? new HashSet(ids0) : new HashSet(); + + IDictionary newFields = meta0 != null ? + new Dictionary(meta0.FieldsMap()) : new Dictionary(newMap.Count); + + // 2. Add new fields. + foreach (KeyValuePair> newEntry in newMap) + { + if (!newIds.Contains(newEntry.Key)) + newIds.Add(newEntry.Key); + + if (!newFields.ContainsKey(newEntry.Value.Item1)) + newFields[newEntry.Value.Item1] = newEntry.Value.Item2; + } + + // 3. Assign new meta. Order is important here: meta must be assigned before field IDs. + _meta = new BinaryType(_typeId, _typeName, newFields, _affKeyFieldName); + _ids = newIds; + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/894057e5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/IBinaryTypeHandler.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/IBinaryTypeHandler.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/IBinaryTypeHandler.cs new file mode 100644 index 0000000..848a775 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/IBinaryTypeHandler.cs @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Apache.Ignite.Core.Impl.Binary.Metadata +{ + using System.Collections.Generic; + + /// + /// Binary type metadata handler. + /// + public interface IBinaryTypeHandler + { + /// + /// Callback invoked when named field is written. + /// + /// Field ID. + /// Field name. + /// Field type ID. + void OnFieldWrite(int fieldId, string fieldName, int typeId); + + /// + /// Callback invoked when object write is finished and it is time to collect missing metadata. + /// + /// Collected metadata. + IDictionary OnObjectWriteFinished(); + } +}