예제 #1
0
        public AllocatedMemoryData Clone(JsonOperationContext context, out TimeSeriesValuesSegment segment)
        {
            // for better reuse let use the const size of 'MaxSegmentSize'
            var memory = context.GetMemory(TimeSeriesStorage.MaxSegmentSize);

            Memory.Set(memory.Address, 0, TimeSeriesStorage.MaxSegmentSize);
            CopyTo(memory.Address);
            segment = new TimeSeriesValuesSegment(memory.Address, _capacity);
            return(memory);
        }
예제 #2
0
 private static DateTime GetLastLiveTimestamp(DocumentsOperationContext context, TimeSeriesValuesSegment segment, DateTime baseline)
 {
     return(segment.NumberOfEntries == segment.NumberOfLiveEntries
         ? segment.GetLastTimestamp(baseline) // all values are alive, so we can get the last value fast
         : segment.YieldAllValues(context, baseline, includeDead: false).Last().Timestamp);
 }
예제 #3
0
        public long UpdateStats(DocumentsOperationContext context, TimeSeriesSliceHolder slicer, CollectionName collection, TimeSeriesValuesSegment segment, DateTime baseline, int modifiedEntries)
        {
            long     previousCount;
            DateTime start, end;

            context.DocumentDatabase.Metrics.TimeSeries.PutsPerSec.MarkSingleThreaded(modifiedEntries);
            context.DocumentDatabase.Metrics.TimeSeries.BytesPutsPerSec.MarkSingleThreaded(segment.NumberOfBytes);

            var table = GetOrCreateTable(context.Transaction.InnerTransaction, collection);

            using (ReadStats(context, table, slicer, out previousCount, out start, out end, out var name))
            {
                var liveEntries = segment.NumberOfLiveEntries;
                if (liveEntries > 0)
                {
                    HandleLiveSegment();
                }

                if (liveEntries == 0)
                {
                    if (TryHandleDeadSegment() == false)
                    {
                        // this ts was completely deleted
                        start = end = default;
                    }
                }

                var count = previousCount + liveEntries;

                using (table.Allocate(out var tvb))
                {
                    tvb.Add(slicer.StatsKey);
                    tvb.Add(GetPolicy(slicer));
                    tvb.Add(Bits.SwapBytes(start.Ticks));
                    tvb.Add(end);
                    tvb.Add(count);
                    tvb.Add(name);

                    table.Set(tvb);
                }

                return(count);
            }

            void HandleLiveSegment()
            {
                if (segment.NumberOfEntries == 1 && start > end)
                {
                    // new series
                    start = end = baseline;
                    return;
                }

                var lastTimestamp = GetLastLiveTimestamp(context, segment, baseline);

                if (lastTimestamp > end)
                {
                    end = lastTimestamp; // found later end
                }
                else
                {
                    var reader = _timeSeriesStorage.GetReader(context, slicer.DocId, slicer.Name, start, DateTime.MaxValue);
                    var last   = reader.Last();

                    var lastValueInCurrentSegment = reader.ReadBaselineAsDateTime() == baseline;
                    end = lastValueInCurrentSegment ? lastTimestamp : last.Timestamp;
                }

                var first = segment.YieldAllValues(context, baseline, includeDead: false).First().Timestamp;

                if (first < start)
                {
                    start = first; // found earlier start
                }
                if (baseline <= start && first >= start)
                {
                    // start was removed
                    start = first;
                }
            }

            bool TryHandleDeadSegment()
            {
                if (previousCount == 0)
                {
                    return(false); // if current and previous are zero it means that this time-series was completely deleted
                }
                var readerOfFirstValue = _timeSeriesStorage.GetReader(context, slicer.DocId, slicer.Name, DateTime.MinValue, DateTime.MaxValue);

                readerOfFirstValue.First();
                var firstValueInCurrentSegment = readerOfFirstValue.ReadBaselineAsDateTime() == baseline;

                var last = segment.GetLastTimestamp(baseline);

                if (baseline <= start && last >= start || firstValueInCurrentSegment)
                {
                    // start was removed, need to find the next start

                    // this segment isn't relevant, so let's get the next one
                    var next   = _timeSeriesStorage.GetReader(context, slicer.DocId, slicer.Name, start, DateTime.MaxValue).NextSegmentBaseline();
                    var reader = _timeSeriesStorage.GetReader(context, slicer.DocId, slicer.Name, next, DateTime.MaxValue);

                    var first = reader.First();
                    if (first == default)
                    {
                        return(false);
                    }

                    start = first.Timestamp;
                }

                var readerOfLastValue = _timeSeriesStorage.GetReader(context, slicer.DocId, slicer.Name, start, DateTime.MaxValue);

                readerOfLastValue.Last();

                var lastValueInCurrentSegment = readerOfLastValue.ReadBaselineAsDateTime() == baseline;

                if (baseline <= end && end <= last || lastValueInCurrentSegment)
                {
                    var lastEntry = _timeSeriesStorage.GetReader(context, slicer.DocId, slicer.Name, start, baseline.AddMilliseconds(-1)).Last();
                    if (lastEntry == default)
                    {
                        return(false);
                    }

                    end = lastEntry.Timestamp;
                }

                return(true);
            }
        }