/** <inheritDoc /> */ public T ToPortable <T>(object obj) { if (obj is IPortableObject) { return((T)obj); } IPortableStream stream = new PortableHeapStream(1024); // Serialize. PortableWriterImpl writer = _marsh.StartMarshal(stream); try { writer.Write(obj); } finally { // Save metadata. _marsh.FinishMarshal(writer); } // Deserialize. stream.Seek(0, SeekOrigin.Begin); return(_marsh.Unmarshal <T>(stream, PortableMode.ForcePortable)); }
/// <summary> /// Gets field value on the given object. /// </summary> /// <param name="pos">Position.</param> /// <param name="builder">Builder.</param> /// <returns>Field value.</returns> private T Field0 <T>(int pos, PortableBuilderImpl builder) { IPortableStream stream = new PortableHeapStream(_data); stream.Seek(pos, SeekOrigin.Begin); return(_marsh.Unmarshal <T>(stream, PortableMode.ForcePortable, builder)); }
/// <summary> /// Process portable object inverting handles if needed. /// </summary> /// <param name="outStream">Output stream.</param> /// <param name="port">Portable.</param> internal void ProcessPortable(IPortableStream outStream, PortableUserObject port) { // Special case: writing portable object with correct inversions. PortableHeapStream inStream = new PortableHeapStream(port.Data); inStream.Seek(port.Offset, SeekOrigin.Begin); // Use fresh context to ensure correct portable inversion. Mutate0(new Context(), inStream, outStream, false, 0, EmptyVals); }
/// <summary> /// Lazy fields initialization routine. /// </summary> private void InitializeFields() { if (_fields == null) { IPortableStream stream = new PortableHeapStream(_data); stream.Seek(_offset + 14, SeekOrigin.Begin); int rawDataOffset = stream.ReadInt(); _fields = PortableUtils.ObjectFields(stream, _typeId, rawDataOffset); } }
/// <summary> /// Process child builder. /// </summary> /// <param name="outStream">Output stream.</param> /// <param name="builder">Builder.</param> internal void ProcessBuilder(IPortableStream outStream, PortableBuilderImpl builder) { PortableHeapStream inStream = new PortableHeapStream(builder._obj.Data); inStream.Seek(builder._obj.Offset, SeekOrigin.Begin); // Builder parent context might be null only in one case: if we never met this group of // builders before. In this case we set context to their parent and track it. Context // cleanup will be performed at the very end of build process. if (builder._parent._ctx == null || builder._parent._ctx.Closed) { builder._parent._ctx = new Context(_parent._ctx); } builder.Mutate(inStream, outStream as PortableHeapStream, builder._desc, builder._hashCode, builder._vals); }
/// <summary> /// Internal deserialization routine. /// </summary> /// <param name="mode">The mode.</param> /// <returns> /// Deserialized object. /// </returns> private T Deserialize <T>(PortableMode mode) { if (_deserialized == null) { IPortableStream stream = new PortableHeapStream(_data); stream.Seek(_offset, SeekOrigin.Begin); T res = _marsh.Unmarshal <T>(stream, mode); IPortableTypeDescriptor desc = _marsh.Descriptor(true, _typeId); if (!desc.KeepDeserialized) { return(res); } _deserialized = res; } return((T)_deserialized); }
/** <inheritDoc /> */ public IPortableObject Build() { PortableHeapStream inStream = new PortableHeapStream(_obj.Data); 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); PortableHeapStream outStream = new PortableHeapStream(len); PortableWriterImpl writer = _portables.Marshaller.StartMarshal(outStream); writer.Builder(this); // All related builders will work in this context with this writer. _parent._ctx = new Context(writer); try { // Write. writer.Write(this, null); // Process metadata. _portables.Marshaller.FinishMarshal(writer); // Create portable object once metadata is processed. return(new PortableUserObject(_portables.Marshaller, outStream.InternalArray, 0, _desc.TypeId, _hashCode)); } finally { // Cleanup. _parent._ctx.Closed = true; } }
/** <inheritdoc /> */ public override bool Equals(object obj) { if (this == obj) { return(true); } PortableUserObject that = obj as PortableUserObject; if (that != null) { if (_data == that._data && _offset == that._offset) { return(true); } // 1. Check hash code and type IDs. if (_hashCode == that._hashCode && _typeId == that._typeId) { // 2. Check if objects have the same field sets. InitializeFields(); that.InitializeFields(); if (_fields.Keys.Count != that._fields.Keys.Count) { return(false); } foreach (int id in _fields.Keys) { if (!that._fields.Keys.Contains(id)) { return(false); } } // 3. Check if objects have the same field values. foreach (KeyValuePair <int, int> field in _fields) { object fieldVal = Field0 <object>(field.Value, null); object thatFieldVal = that.Field0 <object>(that._fields[field.Key], null); if (!Equals(fieldVal, thatFieldVal)) { return(false); } } // 4. Check if objects have the same raw data. IPortableStream stream = new PortableHeapStream(_data); stream.Seek(_offset + 10, SeekOrigin.Begin); int len = stream.ReadInt(); int rawOffset = stream.ReadInt(); IPortableStream thatStream = new PortableHeapStream(that._data); thatStream.Seek(_offset + 10, SeekOrigin.Begin); int thatLen = thatStream.ReadInt(); int thatRawOffset = thatStream.ReadInt(); return(PortableUtils.CompareArrays(_data, _offset + rawOffset, len - rawOffset, that._data, that._offset + thatRawOffset, thatLen - thatRawOffset)); } } return(false); }
/// <summary> /// Transfer bytes from one stream to another. /// </summary> /// <param name="inStream">Input stream.</param> /// <param name="outStream">Output stream.</param> /// <param name="cnt">Bytes count.</param> private static void TransferBytes(PortableHeapStream inStream, IPortableStream outStream, int cnt) { outStream.Write(inStream.InternalArray, inStream.Position, cnt); inStream.Seek(cnt, SeekOrigin.Current); }
/// <summary> /// Internal mutation routine. /// </summary> /// <param name="inStream">Input stream.</param> /// <param name="outStream">Output stream.</param> /// <param name="ctx">Context.</param> /// <param name="changeHash">WHether hash should be changed.</param> /// <param name="hash">New hash.</param> /// <param name="vals">Values to be replaced.</param> /// <returns>Mutated object.</returns> private void Mutate0(Context ctx, PortableHeapStream inStream, IPortableStream outStream, bool changeHash, int hash, IDictionary <int, object> vals) { int inStartPos = inStream.Position; int outStartPos = outStream.Position; byte inHdr = inStream.ReadByte(); if (inHdr == PortableUtils.HdrNull) { outStream.WriteByte(PortableUtils.HdrNull); } else if (inHdr == PortableUtils.HdrHnd) { int inHnd = inStream.ReadInt(); int oldPos = inStartPos - inHnd; int newPos; if (ctx.OldToNew(oldPos, out newPos)) { // Handle is still valid. outStream.WriteByte(PortableUtils.HdrHnd); outStream.WriteInt(outStartPos - newPos); } else { // Handle is invalid, write full object. int inRetPos = inStream.Position; inStream.Seek(oldPos, SeekOrigin.Begin); Mutate0(ctx, inStream, outStream, false, 0, EmptyVals); inStream.Seek(inRetPos, SeekOrigin.Begin); } } else if (inHdr == PortableUtils.HdrFull) { byte inUsrFlag = inStream.ReadByte(); int inTypeId = inStream.ReadInt(); int inHash = inStream.ReadInt(); int inLen = inStream.ReadInt(); int inRawOff = inStream.ReadInt(); int hndPos; if (ctx.AddOldToNew(inStartPos, outStartPos, out hndPos)) { // Object could be cached in parent builder. object cachedVal; if (_parent._cache != null && _parent._cache.TryGetValue(inStartPos, out cachedVal)) { ctx.Writer.Write(cachedVal, null); } else { // New object, write in full form. outStream.WriteByte(PortableUtils.HdrFull); outStream.WriteByte(inUsrFlag); outStream.WriteInt(inTypeId); outStream.WriteInt(changeHash ? hash : inHash); // Skip length and raw offset as they are not known at this point. outStream.Seek(8, SeekOrigin.Current); // Write regular fields. while (inStream.Position < inStartPos + inRawOff) { int inFieldId = inStream.ReadInt(); int inFieldLen = inStream.ReadInt(); int inFieldDataPos = inStream.Position; object fieldVal; bool fieldFound = vals.TryGetValue(inFieldId, out fieldVal); if (!fieldFound || fieldVal != PortableBuilderField.RmvMarkerObj) { outStream.WriteInt(inFieldId); int fieldLenPos = outStream.Position; // Here we will write length later. outStream.Seek(4, SeekOrigin.Current); if (fieldFound) { // Replace field with new value. if (fieldVal != PortableBuilderField.RmvMarkerObj) { ctx.Writer.Write(fieldVal, null); } vals.Remove(inFieldId); } else { // If field was requested earlier, then we must write tracked value if (_parent._cache != null && _parent._cache.TryGetValue(inFieldDataPos, out fieldVal)) { ctx.Writer.Write(fieldVal, null); } else { // Filed is not tracked, re-write as is. Mutate0(ctx, inStream, outStream, false, 0, EmptyVals); } } int fieldEndPos = outStream.Position; outStream.Seek(fieldLenPos, SeekOrigin.Begin); outStream.WriteInt(fieldEndPos - fieldLenPos - 4); outStream.Seek(fieldEndPos, SeekOrigin.Begin); } // Position intput stream pointer after the field. inStream.Seek(inFieldDataPos + inFieldLen, SeekOrigin.Begin); } // Write remaining new fields. foreach (KeyValuePair <int, object> valEntry in vals) { if (valEntry.Value != PortableBuilderField.RmvMarkerObj) { outStream.WriteInt(valEntry.Key); int fieldLenPos = outStream.Position; // Here we will write length later. outStream.Seek(4, SeekOrigin.Current); ctx.Writer.Write(valEntry.Value, null); int fieldEndPos = outStream.Position; outStream.Seek(fieldLenPos, SeekOrigin.Begin); outStream.WriteInt(fieldEndPos - fieldLenPos - 4); outStream.Seek(fieldEndPos, SeekOrigin.Begin); } } // Write raw data. int rawPos = outStream.Position; outStream.Write(inStream.InternalArray, inStartPos + inRawOff, inLen - inRawOff); // Write length and raw data offset. int outResPos = outStream.Position; outStream.Seek(outStartPos + OffsetLen, SeekOrigin.Begin); outStream.WriteInt(outResPos - outStartPos); // Length. outStream.WriteInt(rawPos - outStartPos); // Raw offset. outStream.Seek(outResPos, SeekOrigin.Begin); } } else { // Object has already been written, write as handle. outStream.WriteByte(PortableUtils.HdrHnd); outStream.WriteInt(outStartPos - hndPos); } // Synchronize input stream position. inStream.Seek(inStartPos + inLen, SeekOrigin.Begin); } else { // Try writing as well-known type with fixed size. outStream.WriteByte(inHdr); if (!WriteAsPredefined(inHdr, inStream, outStream, ctx)) { throw new IgniteException("Unexpected header [position=" + (inStream.Position - 1) + ", header=" + inHdr + ']'); } } }
/// <summary> /// Mutate portable object. /// </summary> /// <param name="inStream">Input stream with initial object.</param> /// <param name="outStream">Output stream.</param> /// <param name="desc">Portable type descriptor.</param> /// <param name="hashCode">Hash code.</param> /// <param name="vals">Values.</param> internal void Mutate( PortableHeapStream inStream, PortableHeapStream outStream, IPortableTypeDescriptor desc, int hashCode, IDictionary <string, PortableBuilderField> vals) { // Set correct builder to writer frame. PortableBuilderImpl oldBuilder = _parent._ctx.Writer.Builder(_parent); int streamPos = inStream.Position; try { // Prepare fields. IPortableMetadataHandler metaHnd = _portables.Marshaller.MetadataHandler(desc); IDictionary <int, object> vals0; if (vals == null || vals.Count == 0) { vals0 = EmptyVals; } else { vals0 = new Dictionary <int, object>(vals.Count); foreach (KeyValuePair <string, PortableBuilderField> valEntry in vals) { int fieldId = PortableUtils.FieldId(desc.TypeId, valEntry.Key, desc.NameConverter, desc.Mapper); if (vals0.ContainsKey(fieldId)) { throw new IgniteException("Collision in field ID detected (change field name or " + "define custom ID mapper) [fieldName=" + valEntry.Key + ", fieldId=" + fieldId + ']'); } vals0[fieldId] = valEntry.Value.Value; // Write metadata if: 1) it is enabled for type; 2) type is not null (i.e. it is neither // remove marker, nor a field read through "GetField" method. if (metaHnd != null && valEntry.Value.Type != null) { metaHnd.OnFieldWrite(fieldId, valEntry.Key, TypeId(valEntry.Value.Type)); } } } // Actual processing. Mutate0(_parent._ctx, inStream, outStream, true, hashCode, vals0); // 3. Handle metadata. if (metaHnd != null) { IDictionary <string, int> meta = metaHnd.OnObjectWriteFinished(); if (meta != null) { _parent._ctx.Writer.SaveMetadata(desc.TypeId, desc.TypeName, desc.AffinityKeyFieldName, meta); } } } finally { // Restore builder frame. _parent._ctx.Writer.Builder(oldBuilder); inStream.Seek(streamPos, SeekOrigin.Begin); } }