Feature: Writing Execute Results to Temp File (#35)

* WIP for buffering in temporary file

* Adding support for writing to disk for buffering

* WIP - Adding file reader, factory for reader/writer

* Making long list use generics and implement IEnumerable

* Reading/Writing from file is working

* Removing unused 'skipValue' logic

* More tweaks to file buffer

Adding logic for cleaning up the temp files
Adding fix for empty/null column names

* Adding comments and cleanup

* Unit tests for FileStreamWrapper

* WIP adding more unit tests, and finishing up wiring up the output writers

* Finishing up initial unit tests

* Fixing bugs with long fields

* Squashed commit of the following:

commit df0ffc12a46cb286d801d08689964eac08ad71dd
Author: Benjamin Russell <beruss@microsoft.com>
Date:   Wed Sep 7 14:45:39 2016 -0700

    Removing last bit of async for file writing.

    We're seeing a 8x improvement of file write speeds!

commit 08a4b9f32e825512ca24d5dc03ef5acbf7cc6d94
Author: Benjamin Russell <beruss@microsoft.com>
Date:   Wed Sep 7 11:23:06 2016 -0700

    Removing async wrappers

* Rolling back test code for Program.cs

* Changes as per code review

* Fixing broken unit tests

* More fixes for codereview
This commit is contained in:
Benjamin Russell
2016-09-08 17:55:11 -07:00
committed by GitHub
parent 903eab61d1
commit 8aa3d524fc
24 changed files with 4050 additions and 195 deletions

View File

@@ -3,9 +3,11 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.IO;
using System.Data.SqlClient;
using System.Threading;
using Microsoft.SqlTools.ServiceLayer.Connection;
@@ -16,6 +18,7 @@ using Microsoft.SqlServer.Management.SqlParser.Binder;
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
using Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
using Microsoft.SqlTools.ServiceLayer.Test.Utility;
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
@@ -71,7 +74,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
public static Batch GetBasicExecutedBatch()
{
Batch batch = new Batch(StandardQuery, 1);
Batch batch = new Batch(StandardQuery, 1, GetFileStreamFactory());
batch.Execute(CreateTestConnection(new[] {StandardTestData}, false), CancellationToken.None).Wait();
return batch;
}
@@ -79,11 +82,78 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
public static Query GetBasicExecutedQuery()
{
ConnectionInfo ci = CreateTestConnectionInfo(new[] {StandardTestData}, false);
Query query = new Query(StandardQuery, ci, new QueryExecutionSettings());
Query query = new Query(StandardQuery, ci, new QueryExecutionSettings(), GetFileStreamFactory());
query.Execute().Wait();
return query;
}
#region FileStreamWriteMocking
public static IFileStreamFactory GetFileStreamFactory()
{
Mock<IFileStreamFactory> mock = new Mock<IFileStreamFactory>();
mock.Setup(fsf => fsf.GetReader(It.IsAny<string>()))
.Returns(new ServiceBufferFileStreamReader(new InMemoryWrapper(), It.IsAny<string>()));
mock.Setup(fsf => fsf.GetWriter(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(new ServiceBufferFileStreamWriter(new InMemoryWrapper(), It.IsAny<string>(), 1024,
1024));
return mock.Object;
}
public class InMemoryWrapper : IFileStreamWrapper
{
private readonly byte[] storage = new byte[8192];
private readonly MemoryStream memoryStream;
private bool readingOnly;
public InMemoryWrapper()
{
memoryStream = new MemoryStream(storage);
}
public void Dispose()
{
// We'll dispose this via a special method
}
public void Init(string fileName, int bufferSize, FileAccess fAccess)
{
readingOnly = fAccess == FileAccess.Read;
}
public int ReadData(byte[] buffer, int bytes)
{
return ReadData(buffer, bytes, memoryStream.Position);
}
public int ReadData(byte[] buffer, int bytes, long fileOffset)
{
memoryStream.Seek(fileOffset, SeekOrigin.Begin);
return memoryStream.Read(buffer, 0, bytes);
}
public int WriteData(byte[] buffer, int bytes)
{
if (readingOnly) { throw new InvalidOperationException(); }
memoryStream.Write(buffer, 0, bytes);
memoryStream.Flush();
return bytes;
}
public void Flush()
{
if (readingOnly) { throw new InvalidOperationException(); }
}
public void Close()
{
memoryStream.Dispose();
}
}
#endregion
#region DbConnection Mocking
public static DbCommand CreateTestCommand(Dictionary<string, string>[][] data, bool throwOnRead)
@@ -151,12 +221,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
out ConnectionInfo connInfo
)
{
textDocument = new TextDocumentPosition();
textDocument.TextDocument = new TextDocumentIdentifier();
textDocument.TextDocument.Uri = Common.OwnerUri;
textDocument.Position = new Position();
textDocument.Position.Line = 0;
textDocument.Position.Character = 0;
textDocument = new TextDocumentPosition
{
TextDocument = new TextDocumentIdentifier {Uri = OwnerUri},
Position = new Position
{
Line = 0,
Character = 0
}
};
connInfo = Common.CreateTestConnectionInfo(null, false);
@@ -166,15 +239,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
var binder = BinderProvider.CreateBinder(metadataProvider);
LanguageService.Instance.ScriptParseInfoMap.Add(textDocument.TextDocument.Uri,
new ScriptParseInfo()
new ScriptParseInfo
{
Binder = binder,
MetadataProvider = metadataProvider,
MetadataDisplayInfoProvider = displayInfoProvider
});
scriptFile = new ScriptFile();
scriptFile.ClientFilePath = textDocument.TextDocument.Uri;
scriptFile = new ScriptFile {ClientFilePath = textDocument.TextDocument.Uri};
}
public static ServerConnection GetServerConnection(ConnectionInfo connection)
@@ -206,7 +279,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
OwnerUri = OwnerUri
});
}
return new QueryExecutionService(connectionService);
return new QueryExecutionService(connectionService) {BufferFileStreamFactory = GetFileStreamFactory()};
}
#endregion