in modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs [572:770]
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 + ']');
}
}