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 3B54F1873B for ; Fri, 30 Oct 2015 15:52:12 +0000 (UTC) Received: (qmail 54741 invoked by uid 500); 30 Oct 2015 15:51:59 -0000 Delivered-To: apmail-ignite-commits-archive@ignite.apache.org Received: (qmail 54663 invoked by uid 500); 30 Oct 2015 15:51:59 -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 53666 invoked by uid 99); 30 Oct 2015 15:51:58 -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; Fri, 30 Oct 2015 15:51:58 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 3088CE390C; Fri, 30 Oct 2015 15:51:58 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: agoncharuk@apache.org To: commits@ignite.apache.org Date: Fri, 30 Oct 2015 15:52:37 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [41/52] [abbrv] ignite git commit: IGNITE-1770: Implemented constant-time field lookup on protocol level. http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/cpp/core/src/impl/portable/portable_reader_impl.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core/src/impl/portable/portable_reader_impl.cpp b/modules/platforms/cpp/core/src/impl/portable/portable_reader_impl.cpp index a8196a1..644088b 100644 --- a/modules/platforms/cpp/core/src/impl/portable/portable_reader_impl.cpp +++ b/modules/platforms/cpp/core/src/impl/portable/portable_reader_impl.cpp @@ -35,18 +35,19 @@ namespace ignite namespace portable { PortableReaderImpl::PortableReaderImpl(InteropInputStream* stream, PortableIdResolver* idRslvr, - int32_t pos, bool usrType, int32_t typeId, int32_t hashCode, int32_t len, int32_t rawOff) : + int32_t pos, bool usrType, int32_t typeId, int32_t hashCode, int32_t len, int32_t rawOff, + int32_t footerBegin, int32_t footerEnd) : stream(stream), idRslvr(idRslvr), pos(pos), usrType(usrType), typeId(typeId), - hashCode(hashCode), len(len), rawOff(rawOff), rawMode(false), - elemIdGen(0), elemId(0), elemCnt(-1), elemRead(0) + hashCode(hashCode), len(len), rawOff(rawOff), rawMode(false), elemIdGen(0), elemId(0), + elemCnt(-1), elemRead(0), footerBegin(footerBegin), footerEnd(footerEnd) { // No-op. } PortableReaderImpl::PortableReaderImpl(InteropInputStream* stream) : - stream(stream), idRslvr(NULL), pos(0), usrType(false), typeId(0), hashCode(0), - len(0), rawOff(0), rawMode(true), - elemIdGen(0), elemId(0), elemCnt(-1), elemRead(0) + stream(stream), idRslvr(NULL), pos(0), usrType(false), typeId(0), hashCode(0), len(0), + rawOff(0), rawMode(true), elemIdGen(0), elemId(0), elemCnt(-1), elemRead(0), footerBegin(-1), + footerEnd(-1) { // No-op. } @@ -233,12 +234,14 @@ namespace ignite CheckSingleMode(true); int32_t fieldId = idRslvr->GetFieldId(typeId, fieldName); - int32_t fieldLen = SeekField(fieldId); + int32_t fieldPos = FindField(fieldId); - if (fieldLen > 0) - return ReadNullable(stream, PortableUtils::ReadGuid, IGNITE_TYPE_UUID); + if (fieldPos <= 0) + return Guid(); + + stream->Position(fieldPos); - return Guid(); + return ReadNullable(stream, PortableUtils::ReadGuid, IGNITE_TYPE_UUID); } int32_t PortableReaderImpl::ReadGuidArray(const char* fieldName, Guid* res, const int32_t len) @@ -249,20 +252,60 @@ namespace ignite int32_t pos = stream->Position(); int32_t fieldId = idRslvr->GetFieldId(typeId, fieldName); - int32_t fieldLen = SeekField(fieldId); + int32_t fieldPos = FindField(fieldId); - if (fieldLen > 0) { - int32_t realLen = ReadArrayInternal(res, len, stream, ReadGuidArrayInternal, IGNITE_TYPE_ARRAY_UUID); + if (fieldPos <= 0) + return -1; - // If actual read didn't occur return to initial position so that we do not perform - // N jumps to find the field again, where N is total amount of fields. - if (realLen != -1 && (!res || realLen > len)) - stream->Position(pos); + stream->Position(fieldPos); - return realLen; + int32_t realLen = ReadArrayInternal(res, len, stream, ReadGuidArrayInternal, IGNITE_TYPE_ARRAY_UUID); + + return realLen; + } + + void PortableReaderImpl::ParseHeaderIfNeeded() + { + if (footerBegin) + return; + + InteropStreamPositionGuard posGuard(*stream); + + int8_t hdr = stream->ReadInt8(); + + if (hdr != IGNITE_HDR_FULL) + IGNITE_ERROR_2(ignite::IgniteError::IGNITE_ERR_PORTABLE, "Invalid header: ", hdr); + + int8_t protoVer = stream->ReadInt8(); + + if (protoVer != IGNITE_PROTO_VER) { + IGNITE_ERROR_2(ignite::IgniteError::IGNITE_ERR_PORTABLE, + "Unsupported portable protocol version: ", protoVer); } - return -1; + int16_t flags = stream->ReadInt16(); + int32_t typeId = stream->ReadInt32(); + int32_t hashCode = stream->ReadInt32(); + int32_t len = stream->ReadInt32(); + int32_t schemaId = stream->ReadInt32(); + int32_t schemaOrRawOff = stream->ReadInt32(); + + if (flags & IGNITE_PORTABLE_FLAG_RAW_ONLY) + { + footerBegin = len; + + rawOff = schemaOrRawOff; + } + else + { + footerBegin = schemaOrRawOff; + + rawOff = (len - footerBegin) % 8 ? stream->ReadInt32(pos + len - 4) : schemaOrRawOff; + } + + footerEnd = len - ((len - footerBegin) % 8); + + bool usrType = flags & IGNITE_PORTABLE_FLAG_USER_OBJECT; } void PortableReaderImpl::ReadGuidArrayInternal(InteropInputStream* stream, Guid* res, const int32_t len) @@ -287,20 +330,16 @@ namespace ignite int32_t pos = stream->Position(); int32_t fieldId = idRslvr->GetFieldId(typeId, fieldName); - int32_t fieldLen = SeekField(fieldId); + int32_t fieldPos = FindField(fieldId); - if (fieldLen > 0) { - int32_t realLen = ReadStringInternal(res, len); + if (fieldPos <= 0) + return -1; - // If actual read didn't occur return to initial position so that we do not perform - // N jumps to find the field again, where N is total amount of fields. - if (realLen != -1 && (!res || realLen > len)) - stream->Position(pos); + stream->Position(fieldPos); - return realLen; - } + int32_t realLen = ReadStringInternal(res, len); - return -1; + return realLen; } int32_t PortableReaderImpl::ReadStringArray(int32_t* size) @@ -314,15 +353,18 @@ namespace ignite CheckSingleMode(true); int32_t fieldId = idRslvr->GetFieldId(typeId, fieldName); - int32_t fieldLen = SeekField(fieldId); + int32_t fieldPos = FindField(fieldId); - if (fieldLen > 0) - return StartContainerSession(false, IGNITE_TYPE_ARRAY_STRING, size); - else { + if (fieldPos <= 0) + { *size = -1; return ++elemIdGen; } + + stream->Position(fieldPos); + + return StartContainerSession(false, IGNITE_TYPE_ARRAY_STRING, size); } int32_t PortableReaderImpl::ReadStringElement(int32_t id, char* res, const int32_t len) @@ -389,15 +431,18 @@ namespace ignite CheckSingleMode(true); int32_t fieldId = idRslvr->GetFieldId(typeId, fieldName); - int32_t fieldLen = SeekField(fieldId); + int32_t fieldPos = FindField(fieldId); - if (fieldLen > 0) - return StartContainerSession(false, IGNITE_TYPE_ARRAY, size); - else { + if (fieldPos <= 0) + { *size = -1; return ++elemIdGen; } + + stream->Position(fieldPos); + + return StartContainerSession(false, IGNITE_TYPE_ARRAY, size); } int32_t PortableReaderImpl::ReadCollection(CollectionType* typ, int32_t* size) @@ -418,25 +463,26 @@ namespace ignite CheckSingleMode(true); int32_t fieldId = idRslvr->GetFieldId(typeId, fieldName); - int32_t fieldLen = SeekField(fieldId); + int32_t fieldPos = FindField(fieldId); - if (fieldLen > 0) + if (fieldPos <= 0) { - int32_t id = StartContainerSession(false, IGNITE_TYPE_COLLECTION, size); - - if (*size == -1) - *typ = IGNITE_COLLECTION_UNDEFINED; - else - *typ = static_cast(stream->ReadInt8()); - - return id; - } - else { *typ = IGNITE_COLLECTION_UNDEFINED; *size = -1; return ++elemIdGen; } + + stream->Position(fieldPos); + + int32_t id = StartContainerSession(false, IGNITE_TYPE_COLLECTION, size); + + if (*size == -1) + *typ = IGNITE_COLLECTION_UNDEFINED; + else + *typ = static_cast(stream->ReadInt8()); + + return id; } int32_t PortableReaderImpl::ReadMap(MapType* typ, int32_t* size) @@ -457,25 +503,26 @@ namespace ignite CheckSingleMode(true); int32_t fieldId = idRslvr->GetFieldId(typeId, fieldName); - int32_t fieldLen = SeekField(fieldId); + int32_t fieldPos = FindField(fieldId); - if (fieldLen > 0) + if (fieldPos <= 0) { - int32_t id = StartContainerSession(false, IGNITE_TYPE_MAP, size); - - if (*size == -1) - *typ = IGNITE_MAP_UNDEFINED; - else - *typ = static_cast(stream->ReadInt8()); - - return id; - } - else { *typ = IGNITE_MAP_UNDEFINED; *size = -1; return ++elemIdGen; } + + stream->Position(fieldPos); + + int32_t id = StartContainerSession(false, IGNITE_TYPE_MAP, size); + + if (*size == -1) + *typ = IGNITE_MAP_UNDEFINED; + else + *typ = static_cast(stream->ReadInt8()); + + return id; } CollectionType PortableReaderImpl::ReadCollectionTypeUnprotected() @@ -504,11 +551,13 @@ namespace ignite InteropStreamPositionGuard positionGuard(*stream); int32_t fieldId = idRslvr->GetFieldId(typeId, fieldName); - int32_t fieldLen = SeekField(fieldId); + int32_t fieldPos = FindField(fieldId); - if (fieldLen <= 0) + if (fieldPos <= 0) return IGNITE_COLLECTION_UNDEFINED; + stream->Position(fieldPos); + return ReadCollectionTypeUnprotected(); } @@ -544,11 +593,13 @@ namespace ignite InteropStreamPositionGuard positionGuard(*stream); int32_t fieldId = idRslvr->GetFieldId(typeId, fieldName); - int32_t fieldLen = SeekField(fieldId); + int32_t fieldPos = FindField(fieldId); - if (fieldLen <= 0) + if (fieldPos <= 0) return -1; + stream->Position(fieldPos); + return ReadCollectionSizeUnprotected(); } @@ -635,41 +686,18 @@ namespace ignite return stream; } - int32_t PortableReaderImpl::SeekField(const int32_t fieldId) + int32_t PortableReaderImpl::FindField(const int32_t fieldId) { - // We assume that it is very likely that fields are read in the same - // order as they were initially written. So we start seeking field - // from current stream position making a "loop" up to this position. - int32_t marker = stream->Position(); - - for (int32_t curPos = marker; curPos < pos + rawOff;) - { - int32_t curFieldId = stream->ReadInt32(); - int32_t curFieldLen = stream->ReadInt32(); + InteropStreamPositionGuard streamGuard(*stream); - if (fieldId == curFieldId) - return curFieldLen; - else { - curPos = stream->Position() + curFieldLen; + stream->Position(footerBegin); - stream->Position(curPos); - } - } - - stream->Position(pos + IGNITE_FULL_HDR_LEN); - - for (int32_t curPos = stream->Position(); curPos < marker;) + for (int32_t schemaPos = footerBegin; schemaPos < footerEnd; schemaPos += 8) { - int32_t curFieldId = stream->ReadInt32(); - int32_t curFieldLen = stream->ReadInt32(); + int32_t currentFieldId = stream->ReadInt32(schemaPos); - if (fieldId == curFieldId) - return curFieldLen; - else { - curPos = stream->Position() + curFieldLen; - - stream->Position(curPos); - } + if (fieldId == currentFieldId) + return stream->ReadInt32(schemaPos + 4) + pos; } return -1; http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/cpp/core/src/impl/portable/portable_schema.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core/src/impl/portable/portable_schema.cpp b/modules/platforms/cpp/core/src/impl/portable/portable_schema.cpp new file mode 100644 index 0000000..57c23a7 --- /dev/null +++ b/modules/platforms/cpp/core/src/impl/portable/portable_schema.cpp @@ -0,0 +1,88 @@ +/* +* 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. +*/ + +#include "ignite/impl/portable/portable_schema.h" +#include "ignite/impl/portable/portable_writer_impl.h" + +/** FNV1 hash offset basis. */ +enum { FNV1_OFFSET_BASIS = 0x811C9DC5 }; + +/** FNV1 hash prime. */ +enum { FNV1_PRIME = 0x01000193 }; + +namespace ignite +{ + namespace impl + { + namespace portable + { + PortableSchema::PortableSchema(): id(0), fieldsInfo(new FieldContainer()) + { + // No-op. + } + + PortableSchema::~PortableSchema() + { + delete fieldsInfo; + } + + void PortableSchema::AddField(int32_t fieldId, int32_t offset) + { + if (!id) + { + // Initialize offset when the first field is written. + id = FNV1_OFFSET_BASIS; + } + + // Advance schema hash. + int32_t idAccumulator = id ^ (fieldId & 0xFF); + idAccumulator *= FNV1_PRIME; + idAccumulator ^= (fieldId >> 8) & 0xFF; + idAccumulator *= FNV1_PRIME; + idAccumulator ^= (fieldId >> 16) & 0xFF; + idAccumulator *= FNV1_PRIME; + idAccumulator ^= (fieldId >> 24) & 0xFF; + idAccumulator *= FNV1_PRIME; + + id = idAccumulator; + + PortableSchemaFieldInfo info = { fieldId, offset }; + fieldsInfo->push_back(info); + } + + void PortableSchema::Write(interop::InteropOutputStream& out) const + { + for (FieldContainer::const_iterator i = fieldsInfo->begin(); i != fieldsInfo->end(); ++i) + { + out.WriteInt32(i->id); + out.WriteInt32(i->offset); + } + } + + bool PortableSchema::Empty() const + { + return fieldsInfo->empty(); + } + + void PortableSchema::Clear() + { + id = 0; + fieldsInfo->clear(); + } + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/cpp/core/src/impl/portable/portable_writer_impl.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core/src/impl/portable/portable_writer_impl.cpp b/modules/platforms/cpp/core/src/impl/portable/portable_writer_impl.cpp index b16a934..4b65b4b 100644 --- a/modules/platforms/cpp/core/src/impl/portable/portable_writer_impl.cpp +++ b/modules/platforms/cpp/core/src/impl/portable/portable_writer_impl.cpp @@ -16,6 +16,7 @@ */ #include "ignite/impl/portable/portable_writer_impl.h" +#include "ignite/impl/interop/interop_stream_position_guard.h" #include "ignite/ignite_error.h" using namespace ignite::impl::interop; @@ -29,16 +30,16 @@ namespace ignite namespace portable { PortableWriterImpl::PortableWriterImpl(InteropOutputStream* stream, PortableIdResolver* idRslvr, - PortableMetadataManager* metaMgr, PortableMetadataHandler* metaHnd) : + PortableMetadataManager* metaMgr, PortableMetadataHandler* metaHnd, int32_t start) : stream(stream), idRslvr(idRslvr), metaMgr(metaMgr), metaHnd(metaHnd), typeId(idRslvr->GetTypeId()), - elemIdGen(0), elemId(0), elemCnt(0), elemPos(-1), rawPos(-1) + elemIdGen(0), elemId(0), elemCnt(0), elemPos(-1), rawPos(-1), start(start) { // No-op. } PortableWriterImpl::PortableWriterImpl(InteropOutputStream* stream, PortableMetadataManager* metaMgr) : stream(stream), idRslvr(NULL), metaMgr(metaMgr), metaHnd(NULL), typeId(0), - elemIdGen(0), elemId(0), elemCnt(0), elemPos(-1), rawPos(0) + elemIdGen(0), elemId(0), elemCnt(0), elemPos(-1), rawPos(0), start(stream->Position()) { // No-op. } @@ -240,7 +241,7 @@ namespace ignite CheckRawMode(false); CheckSingleMode(true); - WriteFieldIdAndLength(fieldName, IGNITE_TYPE_UUID, 1 + 16); + WriteFieldId(fieldName, IGNITE_TYPE_UUID); stream->WriteInt8(IGNITE_TYPE_UUID); @@ -256,7 +257,6 @@ namespace ignite if (val) { - stream->WriteInt32(5 + len * 17); stream->WriteInt8(IGNITE_TYPE_ARRAY_UUID); stream->WriteInt32(len); @@ -269,7 +269,6 @@ namespace ignite } else { - stream->WriteInt32(1); stream->WriteInt8(IGNITE_HDR_NULL); } } @@ -298,21 +297,15 @@ namespace ignite if (val) { - int32_t lenPos = stream->Position(); - stream->Position(lenPos + 4); - stream->WriteInt8(IGNITE_TYPE_STRING); stream->WriteBool(false); stream->WriteInt32(len); for (int i = 0; i < len; i++) stream->WriteUInt16(*(val + i)); - - stream->WriteInt32(lenPos, stream->Position() - lenPos - 4); } else { - stream->WriteInt32(1); stream->WriteInt8(IGNITE_HDR_NULL); } } @@ -331,7 +324,7 @@ namespace ignite { StartContainerSession(false); - WriteFieldIdSkipLength(fieldName, IGNITE_TYPE_ARRAY_STRING); + WriteFieldId(fieldName, IGNITE_TYPE_ARRAY_STRING); stream->WriteInt8(IGNITE_TYPE_ARRAY_STRING); stream->Position(stream->Position() + 4); @@ -368,7 +361,7 @@ namespace ignite CheckRawMode(false); CheckSingleMode(true); - WriteFieldIdAndLength(fieldName, IGNITE_TYPE_OBJECT, 1); + WriteFieldId(fieldName, IGNITE_TYPE_OBJECT); stream->WriteInt8(IGNITE_HDR_NULL); } @@ -386,7 +379,7 @@ namespace ignite { StartContainerSession(false); - WriteFieldIdSkipLength(fieldName, IGNITE_TYPE_ARRAY); + WriteFieldId(fieldName, IGNITE_TYPE_ARRAY); stream->WriteInt8(IGNITE_TYPE_ARRAY); stream->Position(stream->Position() + 4); @@ -409,7 +402,7 @@ namespace ignite { StartContainerSession(false); - WriteFieldIdSkipLength(fieldName, IGNITE_TYPE_COLLECTION); + WriteFieldId(fieldName, IGNITE_TYPE_COLLECTION); stream->WriteInt8(IGNITE_TYPE_COLLECTION); stream->Position(stream->Position() + 4); @@ -433,7 +426,7 @@ namespace ignite { StartContainerSession(false); - WriteFieldIdSkipLength(fieldName, IGNITE_TYPE_MAP); + WriteFieldId(fieldName, IGNITE_TYPE_MAP); stream->WriteInt8(IGNITE_TYPE_MAP); stream->Position(stream->Position() + 4); @@ -446,15 +439,7 @@ namespace ignite { CheckSession(id); - if (rawPos == -1) - { - int32_t len = stream->Position() - elemPos - 4; - - stream->WriteInt32(elemPos + 4, len); - stream->WriteInt32(elemPos + 9, elemCnt); - } - else - stream->WriteInt32(elemPos + 1, elemCnt); + stream->WriteInt32(elemPos + 1, elemCnt); elemId = 0; elemCnt = 0; @@ -516,27 +501,14 @@ namespace ignite void PortableWriterImpl::WriteFieldId(const char* fieldName, int32_t fieldTypeId) { int32_t fieldId = idRslvr->GetFieldId(typeId, fieldName); - - stream->WriteInt32(fieldId); + int32_t fieldOff = stream->Position() - start; + + schema.AddField(fieldId, fieldOff); if (metaHnd) metaHnd->OnFieldWritten(fieldId, fieldName, fieldTypeId); } - void PortableWriterImpl::WriteFieldIdSkipLength(const char* fieldName, int32_t fieldTypeId) - { - WriteFieldId(fieldName, fieldTypeId); - - stream->Position(stream->Position() + 4); - } - - void PortableWriterImpl::WriteFieldIdAndLength(const char* fieldName, int32_t fieldTypeId, int32_t len) - { - WriteFieldId(fieldName, fieldTypeId); - - stream->WriteInt32(len); - } - template <> void PortableWriterImpl::WriteTopObject(const int8_t& obj) { @@ -591,6 +563,50 @@ namespace ignite WriteTopObject0(obj, PortableUtils::WriteGuid, IGNITE_TYPE_UUID); } + void PortableWriterImpl::PostWrite() + { + int32_t lenWithoutSchema = stream->Position() - start; + + if (schema.Empty()) + { + InteropStreamPositionGuard guard(*stream); + + stream->Position(start + IGNITE_OFFSET_FLAGS); + stream->WriteInt16(IGNITE_PORTABLE_FLAG_USER_OBJECT | IGNITE_PORTABLE_FLAG_RAW_ONLY); + + stream->WriteInt32(start + IGNITE_OFFSET_LEN, lenWithoutSchema); + stream->WriteInt32(start + IGNITE_OFFSET_SCHEMA_ID, 0); + stream->WriteInt32(start + IGNITE_OFFSET_SCHEMA_OR_RAW_OFF, GetRawPosition() - start); + } + else + { + int32_t schemaId = schema.GetId(); + + WriteAndClearSchema(); + + if (rawPos > 0) + stream->WriteInt32(rawPos - start); + + int32_t length = stream->Position() - start; + + stream->WriteInt32(start + IGNITE_OFFSET_LEN, length); + stream->WriteInt32(start + IGNITE_OFFSET_SCHEMA_ID, schemaId); + stream->WriteInt32(start + IGNITE_OFFSET_SCHEMA_OR_RAW_OFF, lenWithoutSchema); + } + } + + bool PortableWriterImpl::HasSchema() const + { + return !schema.Empty(); + } + + void PortableWriterImpl::WriteAndClearSchema() + { + schema.Write(*stream); + + schema.Clear(); + } + InteropOutputStream* PortableWriterImpl::GetStream() { return stream; http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs index 7815106..c8fd30b 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs @@ -78,7 +78,7 @@ namespace Apache.Ignite.Benchmarks.Portable TypeConfigurations = new List { new PortableTypeConfiguration(typeof (Address)) {MetadataEnabled = true}, - new PortableTypeConfiguration(typeof (TestModel)) {MetadataEnabled = false} + //new PortableTypeConfiguration(typeof (TestModel)) {MetadataEnabled = false} } }); } @@ -90,7 +90,7 @@ namespace Apache.Ignite.Benchmarks.Portable protected override void GetDescriptors(ICollection descs) { descs.Add(BenchmarkOperationDescriptor.Create("WriteAddress", WriteAddress, 1)); - descs.Add(BenchmarkOperationDescriptor.Create("WriteTestModel", WriteTestModel, 1)); + //descs.Add(BenchmarkOperationDescriptor.Create("WriteTestModel", WriteTestModel, 1)); } /// http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj index e4450b6..ffe5d9f 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj @@ -171,6 +171,7 @@ + @@ -179,6 +180,7 @@ + @@ -253,6 +255,9 @@ + + + http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/Fnv1Hash.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/Fnv1Hash.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/Fnv1Hash.cs new file mode 100644 index 0000000..26bbe7c --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/Fnv1Hash.cs @@ -0,0 +1,54 @@ +/* + * 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.Common +{ + /// + /// Fowler–Noll–Vo hash function. + /// + internal static class Fnv1Hash + { + /** Basis. */ + public const int Basis = unchecked((int) 0x811C9DC5); + + /** Prime. */ + public const int Prime = 0x01000193; + + /// + /// Updates the hashcode with next int. + /// + /// The current. + /// The next. + /// Updated hashcode. + public static int Update(int current, int next) + { + current = current ^ (next & 0xFF); + current = current * Prime; + + current = current ^ ((next >> 8) & 0xFF); + current = current * Prime; + + current = current ^ ((next >> 16) & 0xFF); + current = current * Prime; + + current = current ^ ((next >> 24) & 0xFF); + current = current * Prime; + + return current; + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/ResizeableArray.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/ResizeableArray.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/ResizeableArray.cs new file mode 100644 index 0000000..cb432e5 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/ResizeableArray.cs @@ -0,0 +1,70 @@ +/* + * 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.Common +{ + using System.Collections.Generic; + + /// + /// Simple append-only alternative which exposes internal array. + /// + internal class ResizeableArray + { + /** Array. */ + private T[] _arr; + + /** Items count. */ + private int _count; + + /// + /// Constructor. + /// + /// Capacity. + public ResizeableArray(int capacity) + { + _arr = new T[capacity]; + } + + /// + /// Array. + /// + public T[] Array + { + get { return _arr; } + } + + /// + /// Count. + /// + public int Count + { + get { return _count; } + } + + /// + /// Add element. + /// + /// Element. + public void Add(T element) + { + if (_count == _arr.Length) + System.Array.Resize(ref _arr, _arr.Length*2); + + _arr[_count++] = element; + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs index b7ea4d6..44766c2 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs @@ -21,6 +21,7 @@ namespace Apache.Ignite.Core.Impl.Memory using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text; + using Apache.Ignite.Core.Impl.Common; using Apache.Ignite.Core.Impl.Portable.IO; /// @@ -92,6 +93,8 @@ namespace Apache.Ignite.Core.Impl.Memory /** */ public void WriteByteArray(byte[] val) { + IgniteArgumentCheck.NotNull(val, "val"); + fixed (byte* val0 = val) { CopyFromAndShift(val0, val.Length); @@ -107,6 +110,8 @@ namespace Apache.Ignite.Core.Impl.Memory /** */ public void WriteBoolArray(bool[] val) { + IgniteArgumentCheck.NotNull(val, "val"); + fixed (bool* val0 = val) { CopyFromAndShift((byte*)val0, val.Length); @@ -124,6 +129,8 @@ namespace Apache.Ignite.Core.Impl.Memory /** */ public virtual void WriteShortArray(short[] val) { + IgniteArgumentCheck.NotNull(val, "val"); + fixed (short* val0 = val) { CopyFromAndShift((byte*)val0, val.Length << Shift2); @@ -141,6 +148,8 @@ namespace Apache.Ignite.Core.Impl.Memory /** */ public virtual void WriteCharArray(char[] val) { + IgniteArgumentCheck.NotNull(val, "val"); + fixed (char* val0 = val) { CopyFromAndShift((byte*)val0, val.Length << Shift2); @@ -167,6 +176,8 @@ namespace Apache.Ignite.Core.Impl.Memory /** */ public virtual void WriteIntArray(int[] val) { + IgniteArgumentCheck.NotNull(val, "val"); + fixed (int* val0 = val) { CopyFromAndShift((byte*)val0, val.Length << Shift4); @@ -184,6 +195,8 @@ namespace Apache.Ignite.Core.Impl.Memory /** */ public virtual void WriteLongArray(long[] val) { + IgniteArgumentCheck.NotNull(val, "val"); + fixed (long* val0 = val) { CopyFromAndShift((byte*)val0, val.Length << Shift8); @@ -201,6 +214,8 @@ namespace Apache.Ignite.Core.Impl.Memory /** */ public virtual void WriteFloatArray(float[] val) { + IgniteArgumentCheck.NotNull(val, "val"); + fixed (float* val0 = val) { CopyFromAndShift((byte*)val0, val.Length << Shift4); @@ -218,6 +233,8 @@ namespace Apache.Ignite.Core.Impl.Memory /** */ public virtual void WriteDoubleArray(double[] val) { + IgniteArgumentCheck.NotNull(val, "val"); + fixed (double* val0 = val) { CopyFromAndShift((byte*)val0, val.Length << Shift8); @@ -227,6 +244,9 @@ namespace Apache.Ignite.Core.Impl.Memory /** */ public int WriteString(char* chars, int charCnt, int byteCnt, Encoding encoding) { + IgniteArgumentCheck.NotNull(charCnt, "charCnt"); + IgniteArgumentCheck.NotNull(byteCnt, "byteCnt"); + int curPos = EnsureWriteCapacityAndShift(byteCnt); return encoding.GetBytes(chars, charCnt, _data + curPos, byteCnt); @@ -235,6 +255,8 @@ namespace Apache.Ignite.Core.Impl.Memory /** */ public void Write(byte[] src, int off, int cnt) { + IgniteArgumentCheck.NotNull(src, "src"); + fixed (byte* src0 = src) { CopyFromAndShift(src0 + off, cnt); @@ -260,7 +282,6 @@ namespace Apache.Ignite.Core.Impl.Memory } /** */ - public byte[] ReadByteArray(int cnt) { int curPos = EnsureReadCapacityAndShift(cnt); @@ -423,6 +444,8 @@ namespace Apache.Ignite.Core.Impl.Memory /** */ public void Read(byte[] dest, int off, int cnt) { + IgniteArgumentCheck.NotNull(dest, "dest"); + fixed (byte* dest0 = dest) { Read(dest0 + off, cnt); @@ -633,9 +656,9 @@ namespace Apache.Ignite.Core.Impl.Memory } /** */ - public int Remaining() + public int Remaining { - return _len - _pos; + get { return _len - _pos; } } /** */ @@ -675,13 +698,13 @@ namespace Apache.Ignite.Core.Impl.Memory #region ARRAYS /** */ - public byte[] Array() + public byte[] GetArray() { - return ArrayCopy(); + return GetArrayCopy(); } /** */ - public byte[] ArrayCopy() + public byte[] GetArrayCopy() { byte[] res = new byte[_mem.Length]; http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs index 3872773..88a7e22 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs @@ -133,5 +133,10 @@ namespace Apache.Ignite.Core.Impl.Portable /// Path index. /// Recorded updates. void UpdateReadStructure(PortableStructure exp, int pathIdx, IList updates); + + /// + /// Gets the schema. + /// + PortableObjectSchema Schema { get; } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/IPortableStream.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/IPortableStream.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/IPortableStream.cs index 73d5a51..80087e4 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/IPortableStream.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/IPortableStream.cs @@ -289,20 +289,20 @@ namespace Apache.Ignite.Core.Impl.Portable.IO /// /// Gets remaining bytes in the stream. /// - /// Remaining bytes. - int Remaining(); + /// Remaining bytes. + int Remaining { get; } /// /// Gets underlying array, avoiding copying if possible. /// /// Underlying array. - byte[] Array(); + byte[] GetArray(); /// /// Gets underlying data in a new array. /// /// New array with data. - byte[] ArrayCopy(); + byte[] GetArrayCopy(); /// /// Check whether array passed as argument is the same as the stream hosts. http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableAbstractStream.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableAbstractStream.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableAbstractStream.cs index f84b5a3..0cd3342 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableAbstractStream.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableAbstractStream.cs @@ -18,28 +18,16 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { using System; - using System.Diagnostics.CodeAnalysis; using System.IO; - using System.Reflection; using System.Text; + using Apache.Ignite.Core.Impl.Common; + using Apache.Ignite.Core.Impl.Memory; /// /// Base class for managed and unmanaged data streams. /// internal unsafe abstract class PortableAbstractStream : IPortableStream { - /// - /// Array copy delegate. - /// - delegate void MemCopy(byte* a1, byte* a2, int len); - - /** memcpy function handle. */ - private static readonly MemCopy Memcpy; - - /** Whether src and dest arguments are inverted. */ - [SuppressMessage("Microsoft.Performance", "CA1802:UseLiteralsWhereAppropriate")] - private static readonly bool MemcpyInverted; - /** Byte: zero. */ private const byte ByteZero = 0; @@ -56,37 +44,6 @@ namespace Apache.Ignite.Core.Impl.Portable.IO private bool _disposed; /// - /// Static initializer. - /// - [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] - [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] - static PortableAbstractStream() - { - Type type = typeof(Buffer); - - const BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic; - Type[] paramTypes = { typeof(byte*), typeof(byte*), typeof(int) }; - - // Assume .Net 4.5. - MethodInfo mthd = type.GetMethod("Memcpy", flags, null, paramTypes, null); - - MemcpyInverted = true; - - if (mthd == null) - { - // Assume .Net 4.0. - mthd = type.GetMethod("memcpyimpl", flags, null, paramTypes, null); - - MemcpyInverted = false; - - if (mthd == null) - throw new InvalidOperationException("Unable to get memory copy function delegate."); - } - - Memcpy = (MemCopy)Delegate.CreateDelegate(typeof(MemCopy), mthd); - } - - /// /// Write byte. /// /// Byte value. @@ -1076,15 +1033,15 @@ namespace Apache.Ignite.Core.Impl.Portable.IO /// /// Internal read routine. /// + /// Source /// Destination. /// Count. - /// Data (source). /// Amount of bytes written. - protected void ReadInternal(byte* dest, int cnt, byte* data) + protected void ReadInternal(byte* src, byte* dest, int cnt) { - int cnt0 = Math.Min(Remaining(), cnt); + int cnt0 = Math.Min(Remaining, cnt); - CopyMemory(data + Pos, dest, cnt0); + CopyMemory(src + Pos, dest, cnt0); ShiftRead(cnt0); } @@ -1100,10 +1057,10 @@ namespace Apache.Ignite.Core.Impl.Portable.IO /// /// Gets remaining bytes in the stream. /// - /// - /// Remaining bytes. - /// - public abstract int Remaining(); + /// + /// Remaining bytes. + /// + public abstract int Remaining { get; } /// /// Gets underlying array, avoiding copying if possible. @@ -1111,7 +1068,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO /// /// Underlying array. /// - public abstract byte[] Array(); + public abstract byte[] GetArray(); /// /// Gets underlying data in a new array. @@ -1119,7 +1076,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO /// /// New array with data. /// - public abstract byte[] ArrayCopy(); + public abstract byte[] GetArrayCopy(); /// /// Check whether array passed as argument is the same as the stream hosts. @@ -1291,10 +1248,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO /// Length. private static void CopyMemory(byte* src, byte* dest, int len) { - if (MemcpyInverted) - Memcpy.Invoke(dest, src, len); - else - Memcpy.Invoke(src, dest, len); + PlatformMemoryUtils.CopyMemory(src, dest, len); } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableHeapStream.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableHeapStream.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableHeapStream.cs index 690f92c..b7d001e 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableHeapStream.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableHeapStream.cs @@ -18,8 +18,11 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { using System; + using System.Diagnostics; using System.IO; using System.Text; + using Apache.Ignite.Core.Impl.Common; + using Apache.Ignite.Core.Impl.Memory; /// /// Portable onheap stream. @@ -27,7 +30,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO internal unsafe class PortableHeapStream : PortableAbstractStream { /** Data array. */ - protected byte[] Data; + private byte[] _data; /// /// Constructor. @@ -35,7 +38,9 @@ namespace Apache.Ignite.Core.Impl.Portable.IO /// Initial capacity. public PortableHeapStream(int cap) { - Data = new byte[cap]; + Debug.Assert(cap >= 0); + + _data = new byte[cap]; } /// @@ -44,7 +49,9 @@ namespace Apache.Ignite.Core.Impl.Portable.IO /// Data array. public PortableHeapStream(byte[] data) { - Data = data; + Debug.Assert(data != null); + + _data = data; } /** */ @@ -52,7 +59,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { int pos0 = EnsureWriteCapacityAndShift(1); - Data[pos0] = val; + _data[pos0] = val; } /** */ @@ -60,7 +67,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { int pos0 = EnsureReadCapacityAndShift(1); - return Data[pos0]; + return _data[pos0]; } /** */ @@ -68,7 +75,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { int pos0 = EnsureWriteCapacityAndShift(val.Length); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { WriteByteArray0(val, data0 + pos0); } @@ -79,7 +86,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { int pos0 = EnsureReadCapacityAndShift(cnt); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { return ReadByteArray0(cnt, data0 + pos0); } @@ -90,7 +97,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { int pos0 = EnsureWriteCapacityAndShift(val.Length); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { WriteBoolArray0(val, data0 + pos0); } @@ -101,7 +108,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { int pos0 = EnsureReadCapacityAndShift(cnt); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { return ReadBoolArray0(cnt, data0 + pos0); } @@ -112,7 +119,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { int pos0 = EnsureWriteCapacityAndShift(2); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { WriteShort0(val, data0 + pos0); } @@ -123,7 +130,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { int pos0 = EnsureReadCapacityAndShift(2); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { return ReadShort0(data0 + pos0); } @@ -136,7 +143,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO int pos0 = EnsureWriteCapacityAndShift(cnt); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { WriteShortArray0(val, data0 + pos0, cnt); } @@ -149,7 +156,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO int pos0 = EnsureReadCapacityAndShift(cnt0); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { return ReadShortArray0(cnt, data0 + pos0, cnt0); } @@ -162,7 +169,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO int pos0 = EnsureWriteCapacityAndShift(cnt); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { WriteCharArray0(val, data0 + pos0, cnt); } @@ -175,7 +182,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO int pos0 = EnsureReadCapacityAndShift(cnt0); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { return ReadCharArray0(cnt, data0 + pos0, cnt0); } @@ -186,7 +193,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { int pos0 = EnsureWriteCapacityAndShift(4); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { WriteInt0(val, data0 + pos0); } @@ -197,7 +204,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { EnsureWriteCapacity(writePos + 4); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { WriteInt0(val, data0 + writePos); } @@ -208,7 +215,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { int pos0 = EnsureReadCapacityAndShift(4); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { return ReadInt0(data0 + pos0); } @@ -221,7 +228,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO int pos0 = EnsureWriteCapacityAndShift(cnt); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { WriteIntArray0(val, data0 + pos0, cnt); } @@ -234,7 +241,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO int pos0 = EnsureReadCapacityAndShift(cnt0); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { return ReadIntArray0(cnt, data0 + pos0, cnt0); } @@ -247,7 +254,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO int pos0 = EnsureWriteCapacityAndShift(cnt); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { WriteFloatArray0(val, data0 + pos0, cnt); } @@ -260,7 +267,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO int pos0 = EnsureReadCapacityAndShift(cnt0); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { return ReadFloatArray0(cnt, data0 + pos0, cnt0); } @@ -271,7 +278,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { int pos0 = EnsureWriteCapacityAndShift(8); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { WriteLong0(val, data0 + pos0); } @@ -282,7 +289,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { int pos0 = EnsureReadCapacityAndShift(8); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { return ReadLong0(data0 + pos0); } @@ -295,7 +302,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO int pos0 = EnsureWriteCapacityAndShift(cnt); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { WriteLongArray0(val, data0 + pos0, cnt); } @@ -308,7 +315,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO int pos0 = EnsureReadCapacityAndShift(cnt0); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { return ReadLongArray0(cnt, data0 + pos0, cnt0); } @@ -321,7 +328,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO int pos0 = EnsureWriteCapacityAndShift(cnt); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { WriteDoubleArray0(val, data0 + pos0, cnt); } @@ -334,7 +341,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO int pos0 = EnsureReadCapacityAndShift(cnt0); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { return ReadDoubleArray0(cnt, data0 + pos0, cnt0); } @@ -347,7 +354,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO int written; - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { written = WriteString0(chars, charCnt, byteCnt, encoding, data0 + pos0); } @@ -360,7 +367,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO { EnsureWriteCapacity(Pos + cnt); - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { WriteInternal(src, cnt, data0); } @@ -371,30 +378,30 @@ namespace Apache.Ignite.Core.Impl.Portable.IO /** */ public override void Read(byte* dest, int cnt) { - fixed (byte* data0 = Data) + fixed (byte* data0 = _data) { - ReadInternal(dest, cnt, data0); + ReadInternal(data0, dest, cnt); } } /** */ - public override int Remaining() + public override int Remaining { - return Data.Length - Pos; + get { return _data.Length - Pos; } } /** */ - public override byte[] Array() + public override byte[] GetArray() { - return Data; + return _data; } /** */ - public override byte[] ArrayCopy() + public override byte[] GetArrayCopy() { byte[] copy = new byte[Pos]; - Buffer.BlockCopy(Data, 0, copy, 0, Pos); + Buffer.BlockCopy(_data, 0, copy, 0, Pos); return copy; } @@ -402,7 +409,7 @@ namespace Apache.Ignite.Core.Impl.Portable.IO /** */ public override bool IsSameArray(byte[] arr) { - return Data == arr; + return _data == arr; } /** */ @@ -416,32 +423,32 @@ namespace Apache.Ignite.Core.Impl.Portable.IO /// internal byte[] InternalArray { - get { return Data; } + get { return _data; } } /** */ protected override void EnsureWriteCapacity(int cnt) { - if (cnt > Data.Length) + if (cnt > _data.Length) { - int newCap = Capacity(Data.Length, cnt); + int newCap = Capacity(_data.Length, cnt); byte[] data0 = new byte[newCap]; // Copy the whole initial array length here because it can be changed // from Java without position adjusting. - Buffer.BlockCopy(Data, 0, data0, 0, Data.Length); + Buffer.BlockCopy(_data, 0, data0, 0, _data.Length); - Data = data0; + _data = data0; } } /** */ protected override void EnsureReadCapacity(int cnt) { - if (Data.Length - Pos < cnt) + if (_data.Length - Pos < cnt) throw new EndOfStreamException("Not enough data in stream [expected=" + cnt + - ", remaining=" + (Data.Length - Pos) + ']'); + ", remaining=" + (_data.Length - Pos) + ']'); } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs index 9767037..08a1d00 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs @@ -23,6 +23,7 @@ namespace Apache.Ignite.Core.Impl.Portable using System.Diagnostics; using System.IO; using Apache.Ignite.Core.Common; + using Apache.Ignite.Core.Impl.Common; using Apache.Ignite.Core.Impl.Portable.IO; using Apache.Ignite.Core.Impl.Portable.Metadata; using Apache.Ignite.Core.Portable; @@ -357,9 +358,9 @@ namespace Apache.Ignite.Core.Impl.Portable inStream.Seek(_obj.Offset, SeekOrigin.Begin); // Assume that resulting length will be no less than header + [fields_cnt] * 12; - int len = PortableUtils.FullHdrLen + (_vals == null ? 0 : _vals.Count * 12); + int estimatedCapacity = PortableObjectHeader.Size + (_vals == null ? 0 : _vals.Count*12); - PortableHeapStream outStream = new PortableHeapStream(len); + PortableHeapStream outStream = new PortableHeapStream(estimatedCapacity); PortableWriterImpl writer = _portables.Marshaller.StartMarshal(outStream); @@ -377,8 +378,8 @@ namespace Apache.Ignite.Core.Impl.Portable _portables.Marshaller.FinishMarshal(writer); // Create portable object once metadata is processed. - return new PortableUserObject(_portables.Marshaller, outStream.InternalArray, 0, - _desc.TypeId, _hashCode); + return new PortableUserObject(_portables.Marshaller, outStream.InternalArray, 0, + PortableObjectHeader.Read(outStream, 0)); } finally { @@ -568,7 +569,7 @@ namespace Apache.Ignite.Core.Impl.Portable /// New hash. /// Values to be replaced. /// Mutated object. - private void Mutate0(Context ctx, PortableHeapStream inStream, IPortableStream outStream, + private unsafe void Mutate0(Context ctx, PortableHeapStream inStream, IPortableStream outStream, bool changeHash, int hash, IDictionary vals) { int inStartPos = inStream.Position; @@ -605,13 +606,9 @@ namespace Apache.Ignite.Core.Impl.Portable } else if (inHdr == PortableUtils.HdrFull) { - PortableUtils.ValidateProtocolVersion(inStream); - - byte inUsrFlag = inStream.ReadByte(); - int inTypeId = inStream.ReadInt(); - int inHash = inStream.ReadInt(); - int inLen = inStream.ReadInt(); - int inRawOff = inStream.ReadInt(); + var inHeader = PortableObjectHeader.Read(inStream, inStartPos); + + PortableUtils.ValidateProtocolVersion(inHeader.Version); int hndPos; @@ -620,104 +617,106 @@ namespace Apache.Ignite.Core.Impl.Portable // Object could be cached in parent builder. PortableBuilderField cachedVal; - if (_parent._cache != null && _parent._cache.TryGetValue(inStartPos, out cachedVal)) { + if (_parent._cache != null && _parent._cache.TryGetValue(inStartPos, out cachedVal)) + { WriteField(ctx, cachedVal); } else { // New object, write in full form. - outStream.WriteByte(PortableUtils.HdrFull); - outStream.WriteByte(PortableUtils.ProtoVer); - outStream.WriteByte(inUsrFlag); - outStream.WriteInt(inTypeId); - outStream.WriteInt(changeHash ? hash : inHash); + var inSchema = inHeader.ReadSchema(inStream, inStartPos); - // Skip length and raw offset as they are not known at this point. - outStream.Seek(8, SeekOrigin.Current); + var outSchemaLen = vals.Count + (inSchema == null ? 0 : inSchema.Length); + var outSchema = outSchemaLen > 0 + ? new ResizeableArray(outSchemaLen) + : null; - // Write regular fields. - while (inStream.Position < inStartPos + inRawOff) + // Skip header as it is not known at this point. + outStream.Seek(PortableObjectHeader.Size, SeekOrigin.Current); + + if (inSchema != null) { - int inFieldId = inStream.ReadInt(); - int inFieldLen = inStream.ReadInt(); - int inFieldDataPos = inStream.Position; + foreach (var inField in inSchema) + { + PortableBuilderField fieldVal; - PortableBuilderField fieldVal; + var fieldFound = vals.TryGetValue(inField.Id, out fieldVal); - bool fieldFound = vals.TryGetValue(inFieldId, out fieldVal); + if (fieldFound && fieldVal == PortableBuilderField.RmvMarker) + continue; - if (!fieldFound || fieldVal != PortableBuilderField.RmvMarker) - { - outStream.WriteInt(inFieldId); + // ReSharper disable once PossibleNullReferenceException (can't be null) + outSchema.Add(new PortableObjectSchemaField(inField.Id, outStream.Position - outStartPos)); - int fieldLenPos = outStream.Position; // Here we will write length later. - - outStream.Seek(4, SeekOrigin.Current); + if (!fieldFound) + fieldFound = _parent._cache != null && + _parent._cache.TryGetValue(inField.Offset + inStartPos, out fieldVal); if (fieldFound) { - // Replace field with new value. - if (fieldVal != PortableBuilderField.RmvMarker) - WriteField(ctx, fieldVal); + WriteField(ctx, fieldVal); - vals.Remove(inFieldId); + vals.Remove(inField.Id); } else { - // If field was requested earlier, then we must write tracked value - if (_parent._cache != null && _parent._cache.TryGetValue(inFieldDataPos, out fieldVal)) - WriteField(ctx, fieldVal); - else - // Field is not tracked, re-write as is. - Mutate0(ctx, inStream, outStream, false, 0, EmptyVals); - } - - int fieldEndPos = outStream.Position; + // Field is not tracked, re-write as is. + inStream.Seek(inField.Offset + inStartPos, SeekOrigin.Begin); - outStream.Seek(fieldLenPos, SeekOrigin.Begin); - outStream.WriteInt(fieldEndPos - fieldLenPos - 4); - outStream.Seek(fieldEndPos, SeekOrigin.Begin); + Mutate0(ctx, inStream, outStream, false, 0, EmptyVals); + } } - - // Position intput stream pointer after the field. - inStream.Seek(inFieldDataPos + inFieldLen, SeekOrigin.Begin); } // Write remaining new fields. foreach (var valEntry in vals) { - if (valEntry.Value != PortableBuilderField.RmvMarker) - { - outStream.WriteInt(valEntry.Key); + if (valEntry.Value == PortableBuilderField.RmvMarker) + continue; + + // ReSharper disable once PossibleNullReferenceException (can't be null) + outSchema.Add(new PortableObjectSchemaField(valEntry.Key, outStream.Position - outStartPos)); + + WriteField(ctx, valEntry.Value); + } - int fieldLenPos = outStream.Position; // Here we will write length later. + if (outSchema != null && outSchema.Count == 0) + outSchema = null; - outStream.Seek(4, SeekOrigin.Current); + // Write raw data. + int outRawOff = outStream.Position - outStartPos; - WriteField(ctx, valEntry.Value); + int inRawOff = inHeader.GetRawOffset(inStream, inStartPos); + int inRawLen = inHeader.SchemaOffset - inRawOff; - int fieldEndPos = outStream.Position; + if (inRawLen > 0) + outStream.Write(inStream.InternalArray, inStartPos + inRawOff, inRawLen); - outStream.Seek(fieldLenPos, SeekOrigin.Begin); - outStream.WriteInt(fieldEndPos - fieldLenPos - 4); - outStream.Seek(fieldEndPos, SeekOrigin.Begin); - } + // Write schema + int outSchemaOff = outRawOff; + + if (outSchema != null) + { + outSchemaOff = outStream.Position - outStartPos; + + PortableObjectSchemaField.WriteArray(outSchema.Array, outStream, outSchema.Count); + + if (inRawLen > 0) + outStream.WriteInt(outRawOff); } - // Write raw data. - int rawPos = outStream.Position; + var outSchemaId = PortableUtils.GetSchemaId(outSchema); - outStream.Write(inStream.InternalArray, inStartPos + inRawOff, inLen - inRawOff); + var outLen = outStream.Position - outStartPos; - // Write length and raw data offset. - int outResPos = outStream.Position; + var outHash = changeHash ? hash : inHeader.HashCode; - outStream.Seek(outStartPos + PortableUtils.OffsetLen, SeekOrigin.Begin); + var outHeader = new PortableObjectHeader(inHeader.IsUserType, inHeader.TypeId, outHash, + outLen, outSchemaId, outSchemaOff, outSchema == null); - outStream.WriteInt(outResPos - outStartPos); // Length. - outStream.WriteInt(rawPos - outStartPos); // Raw offset. + PortableObjectHeader.Write(outHeader, outStream, outStartPos); - outStream.Seek(outResPos, SeekOrigin.Begin); + outStream.Seek(outStartPos + outLen, SeekOrigin.Begin); // seek to the end of the object } } else @@ -728,7 +727,7 @@ namespace Apache.Ignite.Core.Impl.Portable } // Synchronize input stream position. - inStream.Seek(inStartPos + inLen, SeekOrigin.Begin); + inStream.Seek(inStartPos + inHeader.Length, SeekOrigin.Begin); } else { http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs index 312cefa..8695a3e 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs @@ -63,6 +63,9 @@ namespace Apache.Ignite.Core.Impl.Portable /** Type structure. */ private volatile PortableStructure _readerTypeStructure = PortableStructure.CreateEmpty(); + + /** Type schema. */ + private readonly PortableObjectSchema _schema = new PortableObjectSchema(); /// /// Constructor. @@ -212,5 +215,11 @@ namespace Apache.Ignite.Core.Impl.Portable _readerTypeStructure = _readerTypeStructure.Merge(exp, pathIdx, updates); } } + + /** */ + public PortableObjectSchema Schema + { + get { return _schema; } + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs index a8d7058..5ea7a55 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs @@ -119,7 +119,7 @@ namespace Apache.Ignite.Core.Impl.Portable Marshal(val, stream); - return stream.ArrayCopy(); + return stream.GetArrayCopy(); } /// http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectHeader.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectHeader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectHeader.cs new file mode 100644 index 0000000..b3768a0 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectHeader.cs @@ -0,0 +1,343 @@ +/* + * 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.Portable +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.IO; + using System.Runtime.InteropServices; + using Apache.Ignite.Core.Impl.Portable.IO; + + /// + /// Portable object header structure. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct PortableObjectHeader : IEquatable + { + /** Size, equals to sizeof(PortableObjectHeader) */ + public const int Size = 24; + + /** User type flag */ + private const int FlagUserType = 0x1; + + /** Raw only flag */ + private const int FlagRawOnly = 0x2; + + /** Actual header layout */ + public readonly byte Header; // Header code, always 103 (HdrFull) + public readonly byte Version; // Protocol version + public readonly short Flags; // Flags + public readonly int TypeId; // Type ID + public readonly int HashCode; // Hash code + public readonly int Length; // Length, including header + public readonly int SchemaId; // Schema ID (Fnv1 of field type ids) + public readonly int SchemaOffset; // Schema offset, or raw offset when RawOnly flag is set. + + /// + /// Initializes a new instance of the struct. + /// + /// User type flag. + /// Type ID. + /// Hash code. + /// Length. + /// Schema ID. + /// Schema offset. + /// Raw flag. + public PortableObjectHeader(bool userType, int typeId, int hashCode, int length, int schemaId, int schemaOffset, bool rawOnly) + { + Header = PortableUtils.HdrFull; + Version = PortableUtils.ProtoVer; + + Debug.Assert(schemaOffset <= length); + Debug.Assert(schemaOffset >= Size); + + Flags = (short) (userType ? FlagUserType : 0); + + if (rawOnly) + Flags = (short) (Flags | FlagRawOnly); + + TypeId = typeId; + HashCode = hashCode; + Length = length; + SchemaId = schemaId; + SchemaOffset = schemaOffset; + } + + /// + /// Initializes a new instance of the struct from specified stream. + /// + /// The stream. + private PortableObjectHeader(IPortableStream stream) + { + Header = stream.ReadByte(); + Version = stream.ReadByte(); + Flags = stream.ReadShort(); + Length = stream.ReadInt(); + TypeId = stream.ReadInt(); + HashCode = stream.ReadInt(); + SchemaId = stream.ReadInt(); + SchemaOffset = stream.ReadInt(); + } + + /// + /// Writes this instance to the specified stream. + /// + /// The stream. + private void Write(IPortableStream stream) + { + stream.WriteByte(Header); + stream.WriteByte(Version); + stream.WriteShort(Flags); + stream.WriteInt(Length); + stream.WriteInt(TypeId); + stream.WriteInt(HashCode); + stream.WriteInt(SchemaId); + stream.WriteInt(SchemaOffset); + } + + /// + /// Gets a user type flag. + /// + public bool IsUserType + { + get { return (Flags & FlagUserType) == FlagUserType; } + } + + /// + /// Gets a raw-only flag. + /// + public bool IsRawOnly + { + get { return (Flags & FlagRawOnly) == FlagRawOnly; } + } + + /// + /// Gets a value indicating whether this instance has raw offset. + /// + public bool HasRawOffset + { + get + { + // Odd amount of records in schema => raw offset is the very last 4 bytes in object. + return !IsRawOnly && (((Length - SchemaOffset) >> 2) & 0x1) != 0x0; + } + } + + /// + /// Gets the schema field count. + /// + public int SchemaFieldCount + { + get + { + if (IsRawOnly) + return 0; + + var schemaSize = Length - SchemaOffset; + + if (HasRawOffset) + schemaSize -= 4; + + return schemaSize >> 3; // 8 == PortableObjectSchemaField.Size + } + } + + /// + /// Gets the schema end. + /// + public int GetSchemaEnd(int position) + { + var res = position + Length; + + if (HasRawOffset) + res -= 4; + + return res; + } + + /// + /// Gets the schema start. + /// + public int GetSchemaStart(int position) + { + return IsRawOnly ? GetSchemaEnd(position) : position + SchemaOffset; + } + + /// + /// Gets the raw offset of this object in specified stream. + /// + /// The stream. + /// The position. + /// Raw offset. + public int GetRawOffset(IPortableStream stream, int position) + { + Debug.Assert(stream != null); + + if (!HasRawOffset) + return SchemaOffset; + + stream.Seek(position + Length - 4, SeekOrigin.Begin); + + return stream.ReadInt(); + } + + /// + /// Reads the schema as dictionary according to this header data. + /// + /// The stream. + /// The position. + /// Schema. + public Dictionary ReadSchemaAsDictionary(IPortableStream stream, int position) + { + Debug.Assert(stream != null); + + var schemaSize = SchemaFieldCount; + + if (schemaSize == 0) + return null; + + stream.Seek(position + SchemaOffset, SeekOrigin.Begin); + + var schema = new Dictionary(schemaSize >> 3); + + for (var i = 0; i < schemaSize; i++) + schema.Add(stream.ReadInt(), stream.ReadInt()); + + return schema; + } + + /// + /// Reads the schema according to this header data. + /// + /// The stream. + /// The position. + /// Schema. + public PortableObjectSchemaField[] ReadSchema(IPortableStream stream, int position) + { + Debug.Assert(stream != null); + + var schemaSize = SchemaFieldCount; + + if (schemaSize == 0) + return null; + + stream.Seek(position + SchemaOffset, SeekOrigin.Begin); + + return PortableObjectSchemaField.ReadArray(stream, schemaSize); + } + + /// + /// Writes specified header to a stream. + /// + /// The header. + /// The stream. + /// The position. + public static unsafe void Write(PortableObjectHeader header, IPortableStream stream, int position) + { + Debug.Assert(stream != null); + Debug.Assert(position >= 0); + + stream.Seek(position, SeekOrigin.Begin); + + if (BitConverter.IsLittleEndian) + stream.Write((byte*) &header, Size); + else + header.Write(stream); + } + + /// + /// Reads an instance from stream. + /// + /// The stream. + /// The position. + /// Instance of the header. + public static unsafe PortableObjectHeader Read(IPortableStream stream, int position) + { + Debug.Assert(stream != null); + Debug.Assert(position >= 0); + + stream.Seek(position, SeekOrigin.Begin); + + if (BitConverter.IsLittleEndian) + { + var hdr = new PortableObjectHeader(); + + stream.Read((byte*) &hdr, Size); + + Debug.Assert(hdr.Version == PortableUtils.ProtoVer); + Debug.Assert(hdr.SchemaOffset <= hdr.Length); + Debug.Assert(hdr.SchemaOffset >= Size); + + return hdr; + } + + return new PortableObjectHeader(stream); + } + + /** */ + public bool Equals(PortableObjectHeader other) + { + return Header == other.Header && + Version == other.Version && + Flags == other.Flags && + TypeId == other.TypeId && + HashCode == other.HashCode && + Length == other.Length && + SchemaId == other.SchemaId && + SchemaOffset == other.SchemaOffset; + } + + /** */ + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + + return obj is PortableObjectHeader && Equals((PortableObjectHeader) obj); + } + + /** */ + public override int GetHashCode() + { + unchecked + { + var hashCode = Header.GetHashCode(); + hashCode = (hashCode*397) ^ Version.GetHashCode(); + hashCode = (hashCode*397) ^ Flags.GetHashCode(); + hashCode = (hashCode*397) ^ TypeId; + hashCode = (hashCode*397) ^ HashCode; + hashCode = (hashCode*397) ^ Length; + hashCode = (hashCode*397) ^ SchemaId; + hashCode = (hashCode*397) ^ SchemaOffset; + return hashCode; + } + } + + /** */ + public static bool operator ==(PortableObjectHeader left, PortableObjectHeader right) + { + return left.Equals(right); + } + + /** */ + public static bool operator !=(PortableObjectHeader left, PortableObjectHeader right) + { + return !left.Equals(right); + } + } +}