Beispiel #1
0
        private void ReadMetricsData(
            BinaryReader reader,
            IFrontEndMetricBuilder <TMetadata> metricBuilder,
            ushort version,
            int maxMetricDimensionValueStringsLength)
        {
            long packetTime = 0;

            if (version >= 5)
            {
                packetTime = (long)SerializationUtils.ReadUInt64FromBase128(reader);
            }

            Stream readerStream = reader.BaseStream;

            var metricsCount = reader.ReadUInt32();

            for (var i = 0; i < metricsCount; ++i)
            {
                DateTime timeUtc;
                var      count = 0U;
                var      sum   = default(MetricValueV2);
                var      min   = default(MetricValueV2);
                var      max   = default(MetricValueV2);
                double   sumOfSquareDiffFromMean = 0;

                var metadata = this.ReadMetricMetadataByIndex(reader);

                if (version >= 5)
                {
                    var timeInTicks = (packetTime - SerializationUtils.ReadInt64FromBase128(reader)) * SerializationUtils.OneMinuteInterval;
                    timeUtc = new DateTime(timeInTicks, DateTimeKind.Utc);
                }
                else
                {
                    timeUtc = new DateTime((long)SerializationUtils.ReadUInt64FromBase128(reader), DateTimeKind.Utc);
                }

                for (var j = 0; j < metadata.DimensionsCount; ++j)
                {
                    var dimensionValue = this.ReadStringByIndex(reader);
                    if (dimensionValue.Length > maxMetricDimensionValueStringsLength)
                    {
                        throw new MetricSerializationException($"Dimension value string in the packet exceeds preconfigured length. Packet is corrupted. MaxLength:{maxMetricDimensionValueStringsLength}, Value:{dimensionValue}.", null, true);
                    }

                    this.reusableStringsList.Add(dimensionValue);
                }

                var samplingTypes        = (SamplingTypes)SerializationUtils.ReadUInt32FromBase128(reader);
                var isDouble             = (samplingTypes & SamplingTypes.DoubleValueType) != 0;
                var isDoubleStoredAslong = (samplingTypes & SamplingTypes.DoubleValueStoredAsLongType) != 0;

                if ((samplingTypes & SamplingTypes.Min) != 0)
                {
                    min = this.ReadMetricValue(reader, isDouble, isDoubleStoredAslong);
                }

                if ((samplingTypes & SamplingTypes.Max) != 0)
                {
                    max = this.ReadMetricValue(reader, isDouble, isDoubleStoredAslong);
                }

                if ((samplingTypes & SamplingTypes.Sum) != 0)
                {
                    sum = this.ReadMetricValue(reader, isDouble, isDoubleStoredAslong);
                }

                if ((samplingTypes & SamplingTypes.Count) != 0)
                {
                    count = SerializationUtils.ReadUInt32FromBase128(reader);
                }

                if ((samplingTypes & SamplingTypes.SumOfSquareDiffFromMean) != 0)
                {
                    sumOfSquareDiffFromMean = reader.ReadDouble();
                }

                bool haveHistogram = (samplingTypes & SamplingTypes.Histogram) != 0;
                metricBuilder.BeginMetricCreation(metadata, this.reusableStringsList, timeUtc, samplingTypes, count, sum, min, max, sumOfSquareDiffFromMean);
                this.reusableStringsList.Clear();

                if (haveHistogram)
                {
                    IEnumerable <KeyValuePair <ulong, uint> > histogramBuckets =
                        SerializationUtils.ReadHistogram(reader, hasHistogramSizePrefix: version > 3);

                    this.histogramBuffer.Clear();
                    this.histogramBuffer.AddRange(histogramBuckets);
                    metricBuilder.AssignHistogram(this.histogramBuffer);
                }

                if ((samplingTypes & SamplingTypes.HyperLogLogSketch) != 0)
                {
                    var sizeOfHyperLogLogSketches = reader.ReadInt32();
                    metricBuilder.AssignHyperLogLogSketch(reader, sizeOfHyperLogLogSketches);
                }

                if (version >= 6)
                {
                    bool haveTDigest = (samplingTypes & SamplingTypes.TDigest) != 0;
                    bool readTDigest = false;

                    // starting from version 6, there is a list of TLV-type
                    // (https://en.wikipedia.org/wiki/Type-length-value) tuples in the rest of the serialized metric.

                    // deserialize all of them ignoring the unknown ones.
                    // list TLV values is expected to contain a single end-of-list marker in the end with T = 0x00
                    uint type;
                    while ((type = SerializationUtils.ReadUInt32FromBase128(reader)) != 0x00)
                    {
                        int  length  = (int)SerializationUtils.ReadUInt32FromBase128(reader);
                        long nextPos = readerStream.Position + length;

                        switch (type)
                        {
                        case TDigestPrefixValue:     // 0x74 == 't' (tDigest)
                            if (haveTDigest)
                            {
                                if (!readTDigest)
                                {
                                    metricBuilder.AssignTDigest(reader, length);
                                    readTDigest = true;
                                }
                                else
                                {
                                    // if we already saw tDigest value and see it
                                    // second time it is a sign of a protocol error.
                                    throw new MetricSerializationException("Saw 2 TDigest values for the same metric", null, isInvalidData: true);
                                }
                            }
                            else
                            {
                                // if TLV list contains tDigest but the sampling types does not
                                // it is a protocol error
                                throw new MetricSerializationException("Sampling types do not contain tDigest, but TLV list contains it", null, isInvalidData: true);
                            }

                            break;

                        default:
                            // ignore unknown types
                            break;
                        }

                        // always set the position to point to the next entry.
                        // do not trust the deserializer code to leave the position set correctly
                        // this helps prevent compatibility problems and makes the deserializer
                        // more stable
                        readerStream.Position = nextPos;
                    }

                    if (haveTDigest && !readTDigest)
                    {
                        // if sampling types contain TDigest but we have not seen it in TLV this is
                        // a sign of protocol error
                        throw new MetricSerializationException("Sampling types contain tDigest, but TLV list does not contain it", null, isInvalidData: true);
                    }
                }

                metricBuilder.EndMetricCreation();
            }
        }