Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

Commit e26099d

Browse files
committed
Less granular memory block leasing
1 parent 24d742a commit e26099d

File tree

2 files changed

+115
-79
lines changed

2 files changed

+115
-79
lines changed

src/Microsoft.AspNet.Server.Kestrel/Http/Frame.FeatureCollection.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,15 @@ async Task<Stream> IHttpUpgradeFeature.UpgradeAsync()
291291
}
292292
}
293293

294-
await ProduceStartAndFireOnStarting(immediate: true);
294+
var memoryBlock = Memory2.Lease();
295+
try
296+
{
297+
await ProduceStartAndFireOnStarting(memoryBlock, immediate: true);
298+
}
299+
finally
300+
{
301+
Memory2.Return(memoryBlock);
302+
}
295303

296304
return DuplexStream;
297305
}

src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs

Lines changed: 106 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -272,20 +272,20 @@ public async Task RequestProcessingAsync()
272272

273273
HttpContextFactory.Dispose(httpContext);
274274

275-
await ProduceEnd();
276-
277-
var block = Memory2.Lease();
275+
var memoryBlock = Memory2.Lease();
278276
try
279277
{
280-
var segment = block.Data;
278+
await ProduceEnd(memoryBlock);
279+
280+
var segment = memoryBlock.Data;
281281
while (await RequestBody.ReadAsync(segment.Array, segment.Offset, segment.Count) != 0)
282282
{
283283
// Finish reading the request body in case the app did not.
284284
}
285285
}
286286
finally
287287
{
288-
Memory2.Return(block);
288+
Memory2.Return(memoryBlock);
289289
}
290290
}
291291

@@ -393,19 +393,43 @@ private async Task FireOnCompleted()
393393

394394
public void Flush()
395395
{
396-
ProduceStartAndFireOnStarting(immediate: false).GetAwaiter().GetResult();
396+
var memoryBlock = Memory2.Lease();
397+
try
398+
{
399+
ProduceStartAndFireOnStarting(memoryBlock, immediate: false).GetAwaiter().GetResult();
400+
}
401+
finally
402+
{
403+
Memory2.Return(memoryBlock);
404+
}
397405
SocketOutput.Write(_emptyData, immediate: true);
398406
}
399407

400408
public async Task FlushAsync(CancellationToken cancellationToken)
401409
{
402-
await ProduceStartAndFireOnStarting(immediate: false);
410+
var memoryBlock = Memory2.Lease();
411+
try
412+
{
413+
await ProduceStartAndFireOnStarting(memoryBlock, immediate: false);
414+
}
415+
finally
416+
{
417+
Memory2.Return(memoryBlock);
418+
}
403419
await SocketOutput.WriteAsync(_emptyData, immediate: true, cancellationToken: cancellationToken);
404420
}
405421

406422
public void Write(ArraySegment<byte> data)
407423
{
408-
ProduceStartAndFireOnStarting(immediate: false).GetAwaiter().GetResult();
424+
var memoryBlock = Memory2.Lease();
425+
try
426+
{
427+
ProduceStartAndFireOnStarting(memoryBlock, immediate: false).GetAwaiter().GetResult();
428+
}
429+
finally
430+
{
431+
Memory2.Return(memoryBlock);
432+
}
409433

410434
if (_autoChunk)
411435
{
@@ -423,7 +447,15 @@ public void Write(ArraySegment<byte> data)
423447

424448
public async Task WriteAsync(ArraySegment<byte> data, CancellationToken cancellationToken)
425449
{
426-
await ProduceStartAndFireOnStarting(immediate: false);
450+
var memoryBlock = Memory2.Lease();
451+
try
452+
{
453+
await ProduceStartAndFireOnStarting(memoryBlock, immediate: false);
454+
}
455+
finally
456+
{
457+
Memory2.Return(memoryBlock);
458+
}
427459

428460
if (_autoChunk)
429461
{
@@ -506,7 +538,7 @@ public void ProduceContinue()
506538
}
507539
}
508540

509-
public async Task ProduceStartAndFireOnStarting(bool immediate = true)
541+
public async Task ProduceStartAndFireOnStarting(MemoryPoolBlock2 memoryBlock, bool immediate = true)
510542
{
511543
if (_responseStarted) return;
512544

@@ -519,20 +551,23 @@ public async Task ProduceStartAndFireOnStarting(bool immediate = true)
519551
_applicationException);
520552
}
521553

522-
await ProduceStart(immediate, appCompleted: false);
554+
await ProduceStart(memoryBlock, immediate, appCompleted: false);
523555
}
524556

525-
private Task ProduceStart(bool immediate, bool appCompleted)
557+
private Task ProduceStart(
558+
MemoryPoolBlock2 memoryBlock,
559+
bool immediate,
560+
bool appCompleted)
526561
{
527562
if (_responseStarted) return TaskUtilities.CompletedTask;
528563
_responseStarted = true;
529564

530565
var statusBytes = ReasonPhrases.ToStatusBytes(StatusCode, ReasonPhrase);
531566

532-
return CreateResponseHeader(statusBytes, appCompleted, immediate);
567+
return CreateResponseHeader(statusBytes, memoryBlock, appCompleted, immediate);
533568
}
534569

535-
private async Task ProduceEnd()
570+
private async Task ProduceEnd(MemoryPoolBlock2 memoryBlock)
536571
{
537572
if (_applicationException != null)
538573
{
@@ -552,7 +587,7 @@ private async Task ProduceEnd()
552587
}
553588
}
554589

555-
await ProduceStart(immediate: true, appCompleted: true);
590+
await ProduceStart(memoryBlock, immediate: true, appCompleted: true);
556591

557592
// _autoChunk should be checked after we are sure ProduceStart() has been called
558593
// since ProduceStart() may set _autoChunk to true.
@@ -620,95 +655,88 @@ private static void OutputAsciiBlock(byte[] data, MemoryPoolBlock2 memoryBlock,
620655

621656
private Task CreateResponseHeader(
622657
byte[] statusBytes,
658+
MemoryPoolBlock2 memoryBlock,
623659
bool appCompleted,
624660
bool immediate)
625661
{
626-
var memoryBlock = Memory2.Lease();
627-
try
628-
{
629-
var blockRemaining = memoryBlock.Data.Count;
662+
var blockRemaining = memoryBlock.Data.Count;
630663

631-
OutputAsciiBlock(_httpVersion == HttpVersionType.Http1_1 ? _bytesHttpVersion1_1 : _bytesHttpVersion1_0, memoryBlock, SocketOutput);
664+
OutputAsciiBlock(_httpVersion == HttpVersionType.Http1_1 ? _bytesHttpVersion1_1 : _bytesHttpVersion1_0, memoryBlock, SocketOutput);
632665

633-
OutputAsciiBlock(statusBytes, memoryBlock, SocketOutput);
666+
OutputAsciiBlock(statusBytes, memoryBlock, SocketOutput);
667+
668+
if (_responseHeaders.HasDefaultDate)
669+
{
670+
OutputAsciiBlock(_bytesDate, memoryBlock, SocketOutput);
671+
OutputAsciiBlock(DateHeaderValueManager.GetDateHeaderValueBytes(), memoryBlock, SocketOutput);
672+
OutputAsciiBlock(_bytesEndLine, memoryBlock, SocketOutput);
673+
}
634674

635-
if (_responseHeaders.HasDefaultDate)
675+
foreach (var header in _responseHeaders.AsOutputEnumerable())
676+
{
677+
foreach (var value in header.Value)
636678
{
637-
OutputAsciiBlock(_bytesDate, memoryBlock, SocketOutput);
638-
OutputAsciiBlock(DateHeaderValueManager.GetDateHeaderValueBytes(), memoryBlock, SocketOutput);
679+
OutputAsciiBlock(header.Key, memoryBlock, SocketOutput);
680+
OutputAsciiBlock(value, memoryBlock, SocketOutput);
639681
OutputAsciiBlock(_bytesEndLine, memoryBlock, SocketOutput);
640-
}
641682

642-
foreach (var header in _responseHeaders.AsOutputEnumerable())
643-
{
644-
foreach (var value in header.Value)
683+
if (_responseHeaders.HasConnection && value.IndexOf("close", StringComparison.OrdinalIgnoreCase) != -1)
645684
{
646-
OutputAsciiBlock(header.Key, memoryBlock, SocketOutput);
647-
OutputAsciiBlock(value, memoryBlock, SocketOutput);
648-
OutputAsciiBlock(_bytesEndLine, memoryBlock, SocketOutput);
649-
650-
if (_responseHeaders.HasConnection && value.IndexOf("close", StringComparison.OrdinalIgnoreCase) != -1)
651-
{
652-
_keepAlive = false;
653-
}
685+
_keepAlive = false;
654686
}
655687
}
688+
}
689+
690+
if (_responseHeaders.HasDefaultServer)
691+
{
692+
OutputAsciiBlock(_bytesServer, memoryBlock, SocketOutput);
693+
}
656694

657-
if (_responseHeaders.HasDefaultServer)
695+
if (_keepAlive && !_responseHeaders.HasTransferEncoding && !_responseHeaders.HasContentLength)
696+
{
697+
if (appCompleted)
658698
{
659-
OutputAsciiBlock(_bytesServer, memoryBlock, SocketOutput);
699+
// Don't set the Content-Length or Transfer-Encoding headers
700+
// automatically for HEAD requests or 101, 204, 205, 304 responses.
701+
if (Method != "HEAD" && StatusCanHaveBody(StatusCode))
702+
{
703+
// Since the app has completed and we are only now generating
704+
// the headers we can safely set the Content-Length to 0.
705+
OutputAsciiBlock(_bytesContentLengthZero, memoryBlock, SocketOutput);
706+
}
660707
}
661-
662-
if (_keepAlive && !_responseHeaders.HasTransferEncoding && !_responseHeaders.HasContentLength)
708+
else
663709
{
664-
if (appCompleted)
710+
if (_httpVersion == HttpVersionType.Http1_1)
665711
{
666-
// Don't set the Content-Length or Transfer-Encoding headers
667-
// automatically for HEAD requests or 101, 204, 205, 304 responses.
668-
if (Method != "HEAD" && StatusCanHaveBody(StatusCode))
669-
{
670-
// Since the app has completed and we are only now generating
671-
// the headers we can safely set the Content-Length to 0.
672-
OutputAsciiBlock(_bytesContentLengthZero, memoryBlock, SocketOutput);
673-
}
712+
_autoChunk = true;
713+
OutputAsciiBlock(_bytesTransferEncodingChunked, memoryBlock, SocketOutput);
674714
}
675715
else
676716
{
677-
if (_httpVersion == HttpVersionType.Http1_1)
678-
{
679-
_autoChunk = true;
680-
OutputAsciiBlock(_bytesTransferEncodingChunked, memoryBlock, SocketOutput);
681-
}
682-
else
683-
{
684-
_keepAlive = false;
685-
}
717+
_keepAlive = false;
686718
}
687719
}
720+
}
688721

689-
if (_keepAlive == false && _responseHeaders.HasConnection == false && _httpVersion == HttpVersionType.Http1_1)
690-
{
691-
OutputAsciiBlock(_bytesConnectionClose, memoryBlock, SocketOutput);
692-
}
693-
else if (_keepAlive && _responseHeaders.HasConnection == false && _httpVersion == HttpVersionType.Http1_0)
694-
{
695-
OutputAsciiBlock(_bytesConnectionKeepAlive, memoryBlock, SocketOutput);
696-
}
697-
else
698-
{
699-
OutputAsciiBlock(_bytesEndLine, memoryBlock, SocketOutput);
700-
}
701-
702-
return SocketOutput.WriteAsync(
703-
(memoryBlock.Start == memoryBlock.End) ?
704-
default(ArraySegment<byte>) :
705-
new ArraySegment<byte>(memoryBlock.Array, memoryBlock.Start, memoryBlock.End - memoryBlock.Start),
706-
immediate);
722+
if (_keepAlive == false && _responseHeaders.HasConnection == false && _httpVersion == HttpVersionType.Http1_1)
723+
{
724+
OutputAsciiBlock(_bytesConnectionClose, memoryBlock, SocketOutput);
707725
}
708-
finally
726+
else if (_keepAlive && _responseHeaders.HasConnection == false && _httpVersion == HttpVersionType.Http1_0)
709727
{
710-
Memory2.Return(memoryBlock);
728+
OutputAsciiBlock(_bytesConnectionKeepAlive, memoryBlock, SocketOutput);
711729
}
730+
else
731+
{
732+
OutputAsciiBlock(_bytesEndLine, memoryBlock, SocketOutput);
733+
}
734+
735+
return SocketOutput.WriteAsync(
736+
(memoryBlock.Start == memoryBlock.End) ?
737+
default(ArraySegment<byte>) :
738+
new ArraySegment<byte>(memoryBlock.Array, memoryBlock.Start, memoryBlock.End - memoryBlock.Start),
739+
immediate);
712740
}
713741

714742
private bool TakeStartLine(SocketInput input)

0 commit comments

Comments
 (0)