• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 
3 // Copyright 2019 The gRPC Authors
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #endregion
18 
19 using Grpc.Core.Utils;
20 using System;
21 using System.Threading;
22 
23 using System.Buffers;
24 
25 namespace Grpc.Core.Internal
26 {
27     internal class ReusableSliceBuffer
28     {
29         public const int MaxCachedSegments = 1024;  // ~4MB payload for 4K slices
30 
31         readonly SliceSegment[] cachedSegments = new SliceSegment[MaxCachedSegments];
32         int populatedSegmentCount;
33 
PopulateFrom(IBufferReader bufferReader)34         public ReadOnlySequence<byte> PopulateFrom(IBufferReader bufferReader)
35         {
36             populatedSegmentCount = 0;
37             long offset = 0;
38             SliceSegment prevSegment = null;
39             while (bufferReader.TryGetNextSlice(out Slice slice))
40             {
41                 // Initialize cached segment if still null or just allocate a new segment if we already reached MaxCachedSegments
42                 var current = populatedSegmentCount < cachedSegments.Length ? cachedSegments[populatedSegmentCount] : new SliceSegment();
43                 if (current == null)
44                 {
45                     current = cachedSegments[populatedSegmentCount] = new SliceSegment();
46                 }
47 
48                 current.Reset(slice, offset);
49                 prevSegment?.SetNext(current);
50 
51                 populatedSegmentCount ++;
52                 offset += slice.Length;
53                 prevSegment = current;
54             }
55 
56             // Not necessary for ending the ReadOnlySequence, but for making sure we
57             // don't keep more than MaxCachedSegments alive.
58             prevSegment?.SetNext(null);
59 
60             if (populatedSegmentCount == 0)
61             {
62                 return ReadOnlySequence<byte>.Empty;
63             }
64 
65             var firstSegment = cachedSegments[0];
66             var lastSegment = prevSegment;
67             return new ReadOnlySequence<byte>(firstSegment, 0, lastSegment, lastSegment.Memory.Length);
68         }
69 
Invalidate()70         public void Invalidate()
71         {
72             if (populatedSegmentCount == 0)
73             {
74                 return;
75             }
76             var segment = cachedSegments[0];
77             while (segment != null)
78             {
79                 segment.Reset(new Slice(IntPtr.Zero, 0), 0);
80                 var nextSegment = (SliceSegment) segment.Next;
81                 segment.SetNext(null);
82                 segment = nextSegment;
83             }
84             populatedSegmentCount = 0;
85         }
86 
87         // Represents a segment in ReadOnlySequence
88         // Segment is backed by Slice and the instances are reusable.
89         private class SliceSegment : ReadOnlySequenceSegment<byte>
90         {
91             readonly SliceMemoryManager pointerMemoryManager = new SliceMemoryManager();
92 
Reset(Slice slice, long runningIndex)93             public void Reset(Slice slice, long runningIndex)
94             {
95                 pointerMemoryManager.Reset(slice);
96                 Memory = pointerMemoryManager.Memory;  // maybe not always necessary
97                 RunningIndex = runningIndex;
98             }
99 
SetNext(ReadOnlySequenceSegment<byte> next)100             public void SetNext(ReadOnlySequenceSegment<byte> next)
101             {
102                 Next = next;
103             }
104         }
105     }
106 }
107