/// <summary> /// Seeks the field by name. /// </summary> private bool SeekField(string fieldName) { if (_frame.Raw) { throw new BinaryObjectException("Cannot read named fields after raw data is read."); } if (!_frame.Hdr.HasSchema) { return(false); } var actionId = _frame.Struct.CurStructAction; var fieldId = _frame.Struct.GetFieldId(fieldName); if (_frame.Schema == null || actionId >= _frame.Schema.Length || fieldId != _frame.Schema[actionId]) { _frame.SchemaMap = _frame.SchemaMap ?? BinaryObjectSchemaSerializer.ReadSchema(Stream, _frame.Pos, _frame.Hdr, () => _frame.Schema).ToDictionary(); _frame.Schema = null; // read order is different, ignore schema for future reads int pos; if (!_frame.SchemaMap.TryGetValue(fieldId, out pos)) { return(false); } Stream.Seek(pos + _frame.Pos, SeekOrigin.Begin); } return(true); }
/// <summary> /// Lazy fields initialization routine. /// </summary> private void InitializeFields(IBinaryTypeDescriptor desc = null) { if (_fields != null) { return; } desc = desc ?? _marsh.GetDescriptor(true, _header.TypeId); using (var stream = new BinaryHeapStream(_data)) { var hdr = BinaryObjectHeader.Read(stream, _offset); _fields = BinaryObjectSchemaSerializer.ReadSchema(stream, _offset, hdr, desc.Schema, _marsh) .ToDictionary() ?? EmptyFields; } }
/// <summary> /// Sets the current schema. /// </summary> private void SetCurSchema(IBinaryTypeDescriptor desc) { _frame.SchemaMap = null; if (_frame.Hdr.HasSchema) { _frame.Schema = desc.Schema.Get(_frame.Hdr.SchemaId); if (_frame.Schema == null) { _frame.Schema = BinaryObjectSchemaSerializer.GetFieldIds(_frame.Hdr, Marshaller.Ignite, Stream, _frame.Pos); desc.Schema.Add(_frame.Hdr.SchemaId, _frame.Schema); } } else { _frame.Schema = null; } }
/// <summary> /// Writes collected schema to the stream and pops it. /// </summary> /// <param name="stream">The stream.</param> /// <param name="schemaOffset">The schema offset.</param> /// <param name="schemaId">The schema identifier.</param> /// <param name="flags">Flags according to offset sizes.</param> /// <returns> /// True if current schema was non empty; false otherwise. /// </returns> public bool WriteSchema(IBinaryStream stream, int schemaOffset, out int schemaId, ref BinaryObjectHeader.Flag flags) { schemaId = Fnv1Hash.Basis; var count = _idx - schemaOffset; if (count == 0) { return(false); } flags |= BinaryObjectSchemaSerializer.WriteSchema(_fields, stream, schemaOffset, count, (flags & BinaryObjectHeader.Flag.CompactFooter) == BinaryObjectHeader.Flag.CompactFooter); for (var i = schemaOffset; i < _idx; i++) { schemaId = Fnv1Hash.Update(schemaId, _fields[i].Id); } return(true); }
/// <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="vals">Values to be replaced.</param> /// <returns>Mutated object.</returns> private void Mutate0(Context ctx, BinaryHeapStream inStream, IBinaryStream outStream, bool changeHash, IDictionary <int, BinaryBuilderField> vals) { int inStartPos = inStream.Position; int outStartPos = outStream.Position; byte inHdr = inStream.ReadByte(); if (inHdr == BinaryUtils.HdrNull) { outStream.WriteByte(BinaryUtils.HdrNull); } else if (inHdr == BinaryUtils.HdrHnd) { int inHnd = inStream.ReadInt(); int oldPos = inStartPos - inHnd; int newPos; if (ctx.OldToNew(oldPos, out newPos)) { // Handle is still valid. outStream.WriteByte(BinaryUtils.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, EmptyVals); inStream.Seek(inRetPos, SeekOrigin.Begin); } } else if (inHdr == BinaryUtils.HdrFull) { var inHeader = BinaryObjectHeader.Read(inStream, inStartPos); BinaryUtils.ValidateProtocolVersion(inHeader.Version); int hndPos; if (ctx.AddOldToNew(inStartPos, outStartPos, out hndPos)) { // Object could be cached in parent builder. BinaryBuilderField cachedVal; if (_parent._cache != null && _parent._cache.TryGetValue(inStartPos, out cachedVal)) { WriteField(ctx, cachedVal); } else { // New object, write in full form. var inSchema = BinaryObjectSchemaSerializer.ReadSchema(inStream, inStartPos, inHeader, _desc.Schema, _binary.Marshaller.Ignite); var outSchema = BinaryObjectSchemaHolder.Current; var schemaIdx = outSchema.PushSchema(); try { // Skip header as it is not known at this point. outStream.Seek(BinaryObjectHeader.Size, SeekOrigin.Current); if (inSchema != null) { foreach (var inField in inSchema) { BinaryBuilderField fieldVal; var fieldFound = vals.TryGetValue(inField.Id, out fieldVal); if (fieldFound && fieldVal == BinaryBuilderField.RmvMarker) { continue; } outSchema.PushField(inField.Id, outStream.Position - outStartPos); if (!fieldFound) { fieldFound = _parent._cache != null && _parent._cache.TryGetValue(inField.Offset + inStartPos, out fieldVal); } if (fieldFound) { WriteField(ctx, fieldVal); vals.Remove(inField.Id); } else { // Field is not tracked, re-write as is. inStream.Seek(inField.Offset + inStartPos, SeekOrigin.Begin); Mutate0(ctx, inStream, outStream, false, EmptyVals); } } } // Write remaining new fields. foreach (var valEntry in vals) { if (valEntry.Value == BinaryBuilderField.RmvMarker) { continue; } outSchema.PushField(valEntry.Key, outStream.Position - outStartPos); WriteField(ctx, valEntry.Value); } var flags = inHeader.IsUserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None; if (inHeader.IsCustomDotNetType) { flags |= BinaryObjectHeader.Flag.CustomDotNetType; } // Write raw data. int outRawOff = outStream.Position - outStartPos; if (inHeader.HasRaw) { var inRawOff = inHeader.GetRawOffset(inStream, inStartPos); var inRawLen = inHeader.SchemaOffset - inRawOff; flags |= BinaryObjectHeader.Flag.HasRaw; outStream.Write(inStream.InternalArray, inStartPos + inRawOff, inRawLen); } // Write schema int outSchemaOff = outRawOff; var schemaPos = outStream.Position; int outSchemaId; if (inHeader.IsCompactFooter) { flags |= BinaryObjectHeader.Flag.CompactFooter; } var hasSchema = outSchema.WriteSchema(outStream, schemaIdx, out outSchemaId, ref flags); if (hasSchema) { outSchemaOff = schemaPos - outStartPos; flags |= BinaryObjectHeader.Flag.HasSchema; if (inHeader.HasRaw) { outStream.WriteInt(outRawOff); } if (_desc.Schema.Get(outSchemaId) == null) { _desc.Schema.Add(outSchemaId, outSchema.GetSchema(schemaIdx)); } } var outLen = outStream.Position - outStartPos; var outHash = inHeader.HashCode; if (changeHash) { // Get from identity resolver. outHash = BinaryArrayEqualityComparer.GetHashCode(outStream, outStartPos + BinaryObjectHeader.Size, schemaPos - outStartPos - BinaryObjectHeader.Size); } var outHeader = new BinaryObjectHeader(inHeader.TypeId, outHash, outLen, outSchemaId, outSchemaOff, flags); BinaryObjectHeader.Write(outHeader, outStream, outStartPos); outStream.Seek(outStartPos + outLen, SeekOrigin.Begin); // seek to the end of the object } finally { outSchema.PopSchema(schemaIdx); } } } else { // Object has already been written, write as handle. outStream.WriteByte(BinaryUtils.HdrHnd); outStream.WriteInt(outStartPos - hndPos); } // Synchronize input stream position. inStream.Seek(inStartPos + inHeader.Length, 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 + ']'); } } }