Improve IndirectStorage allocations

Make sure rented arrays are returned and remove delegate allocations by using lambda functions
This commit is contained in:
Alex Barney 2021-12-04 01:57:55 -07:00
parent 40925034e1
commit 921fbab17a
3 changed files with 37 additions and 51 deletions

View file

@ -702,7 +702,7 @@ public partial class BucketTree : IDisposable
return ResultFs.OutOfRange.Log(); return ResultFs.OutOfRange.Log();
// Create a pooled buffer for our scan. // Create a pooled buffer for our scan.
var pool = new PooledBuffer((int)_nodeSize, 1); using var pool = new PooledBuffer((int)_nodeSize, 1);
var buffer = Span<byte>.Empty; var buffer = Span<byte>.Empty;
Result rc = _entryStorage.GetSize(out long entryStorageSize); Result rc = _entryStorage.GetSize(out long entryStorageSize);

View file

@ -179,25 +179,21 @@ public class IndirectStorage : IStorage
if (destination.Length == 0) if (destination.Length == 0)
return Result.Success; return Result.Success;
var closure = new OperatePerEntryClosure(); var closure = new OperatePerEntryClosure { OutBuffer = destination, Offset = offset };
closure.OutBuffer = destination;
closure.Offset = offset; Result rc = OperatePerEntry(offset, destination.Length, enableContinuousReading: true, verifyEntryRanges: true, ref closure,
static (ref ValueSubStorage storage, long physicalOffset, long virtualOffset, long size, ref OperatePerEntryClosure entryClosure) =>
{
int bufferPosition = (int)(virtualOffset - entryClosure.Offset);
Result rc = storage.Read(physicalOffset, entryClosure.OutBuffer.Slice(bufferPosition, (int)size));
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
});
Result rc = OperatePerEntry(offset, destination.Length, ReadImpl, ref closure, enableContinuousReading: true,
verifyEntryRanges: true);
if (rc.IsFailure()) return rc.Miss(); if (rc.IsFailure()) return rc.Miss();
return Result.Success; return Result.Success;
static Result ReadImpl(ref ValueSubStorage storage, long physicalOffset, long virtualOffset, long processSize,
ref OperatePerEntryClosure closure)
{
int bufferPosition = (int)(virtualOffset - closure.Offset);
Result rc = storage.Read(physicalOffset, closure.OutBuffer.Slice(bufferPosition, (int)processSize));
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
} }
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source) protected override Result DoWrite(long offset, ReadOnlySpan<byte> source)
@ -328,24 +324,19 @@ public class IndirectStorage : IStorage
if (!_table.IsEmpty()) if (!_table.IsEmpty())
{ {
var closure = new OperatePerEntryClosure(); var closure = new OperatePerEntryClosure { OperationId = operationId, InBuffer = inBuffer };
closure.OperationId = operationId;
closure.InBuffer = inBuffer;
static Result QueryRangeImpl(ref ValueSubStorage storage, long physicalOffset, rc = OperatePerEntry(offset, size, enableContinuousReading: false, verifyEntryRanges: true, ref closure,
long virtualOffset, long processSize, ref OperatePerEntryClosure closure) static (ref ValueSubStorage storage, long physicalOffset, long virtualOffset, long processSize, ref OperatePerEntryClosure closure) =>
{ {
Unsafe.SkipInit(out QueryRangeInfo currentInfo); Unsafe.SkipInit(out QueryRangeInfo currentInfo);
Result rc = storage.OperateRange(SpanHelpers.AsByteSpan(ref currentInfo), Result rc = storage.OperateRange(SpanHelpers.AsByteSpan(ref currentInfo),
closure.OperationId, physicalOffset, processSize, closure.InBuffer); closure.OperationId, physicalOffset, processSize, closure.InBuffer);
if (rc.IsFailure()) return rc.Miss(); if (rc.IsFailure()) return rc.Miss();
closure.InfoMerged.Merge(in currentInfo); closure.InfoMerged.Merge(in currentInfo);
return Result.Success; return Result.Success;
} });
rc = OperatePerEntry(offset, size, QueryRangeImpl, ref closure, enableContinuousReading: false,
verifyEntryRanges: true);
if (rc.IsFailure()) return rc.Miss(); if (rc.IsFailure()) return rc.Miss();
SpanHelpers.AsByteSpan(ref closure.InfoMerged).CopyTo(outBuffer); SpanHelpers.AsByteSpan(ref closure.InfoMerged).CopyTo(outBuffer);
@ -371,8 +362,8 @@ public class IndirectStorage : IStorage
public QueryRangeInfo InfoMerged; public QueryRangeInfo InfoMerged;
} }
protected Result OperatePerEntry(long offset, long size, OperatePerEntryFunc func, protected Result OperatePerEntry(long offset, long size, bool enableContinuousReading, bool verifyEntryRanges,
ref OperatePerEntryClosure closure, bool enableContinuousReading, bool verifyEntryRanges) ref OperatePerEntryClosure closure, OperatePerEntryFunc func)
{ {
// Validate preconditions // Validate preconditions
Assert.SdkRequiresLessEqual(0, offset); Assert.SdkRequiresLessEqual(0, offset);
@ -391,9 +382,9 @@ public class IndirectStorage : IStorage
return ResultFs.OutOfRange.Log(); return ResultFs.OutOfRange.Log();
// Find the offset in our tree // Find the offset in our tree
var visitor = new BucketTree.Visitor(); using var visitor = new BucketTree.Visitor();
rc = _table.Find(ref visitor, offset); rc = _table.Find(ref visitor.Ref, offset);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
long entryOffset = visitor.Get<Entry>().GetVirtualOffset(); long entryOffset = visitor.Get<Entry>().GetVirtualOffset();

View file

@ -108,25 +108,20 @@ public class SparseStorage : IndirectStorage
} }
else else
{ {
var closure = new OperatePerEntryClosure(); var closure = new OperatePerEntryClosure { OutBuffer = destination, Offset = offset };
closure.OutBuffer = destination;
closure.Offset = offset;
Result rc = OperatePerEntry(offset, destination.Length, ReadImpl, ref closure, Result rc = OperatePerEntry(offset, destination.Length, enableContinuousReading: false, verifyEntryRanges: true, ref closure,
enableContinuousReading: false, verifyEntryRanges: true); static (ref ValueSubStorage storage, long physicalOffset, long virtualOffset, long size, ref OperatePerEntryClosure closure) =>
{
int bufferPosition = (int)(virtualOffset - closure.Offset);
Result rc = storage.Read(physicalOffset, closure.OutBuffer.Slice(bufferPosition, (int)size));
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
});
if (rc.IsFailure()) return rc.Miss(); if (rc.IsFailure()) return rc.Miss();
} }
return Result.Success; return Result.Success;
static Result ReadImpl(ref ValueSubStorage storage, long physicalOffset, long virtualOffset, long processSize,
ref OperatePerEntryClosure closure)
{
int bufferPosition = (int)(virtualOffset - closure.Offset);
Result rc = storage.Read(physicalOffset, closure.OutBuffer.Slice(bufferPosition, (int)processSize));
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
} }
} }