mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-20 09:35:38 -05:00
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:
259
src/Microsoft.SqlTools.ServiceLayer/Utility/LongList.cs
Normal file
259
src/Microsoft.SqlTools.ServiceLayer/Utility/LongList.cs
Normal file
@@ -0,0 +1,259 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection class that permits storage of over <c>int.MaxValue</c> items. This is performed
|
||||
/// by using a 2D list of lists. The internal lists are only initialized as necessary. This
|
||||
/// collection implements IEnumerable to make it easier to run LINQ queries against it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is based on code from $\Data Tools\SSMS_Main\sql\ssms\core\DataStorage\ArrayList64.cs
|
||||
/// with additions to bring it up to .NET 4.5 standards
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">Type of the values to store</typeparam>
|
||||
public class LongList<T> : IEnumerable<T>
|
||||
{
|
||||
#region Member Variables
|
||||
|
||||
private List<List<T>> expandedList;
|
||||
private readonly List<T> shortList;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new long list
|
||||
/// </summary>
|
||||
public LongList()
|
||||
{
|
||||
shortList = new List<T>();
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// The total number of elements in the array
|
||||
/// </summary>
|
||||
public long Count { get; private set; }
|
||||
|
||||
public T this[long index]
|
||||
{
|
||||
get { return GetItem(index); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified value to the end of the list
|
||||
/// </summary>
|
||||
/// <param name="val">Value to add to the list</param>
|
||||
/// <returns>Index of the item that was just added</returns>
|
||||
public long Add(T val)
|
||||
{
|
||||
if (Count <= int.MaxValue)
|
||||
{
|
||||
shortList.Add(val);
|
||||
}
|
||||
else // need to split values into several arrays
|
||||
{
|
||||
if (expandedList == null)
|
||||
{
|
||||
// very inefficient so delay as much as possible
|
||||
// immediately add 0th array
|
||||
expandedList = new List<List<T>> {shortList};
|
||||
}
|
||||
|
||||
int arrayIndex = (int)(Count/int.MaxValue); // 0 based
|
||||
|
||||
List<T> arr;
|
||||
if (expandedList.Count <= arrayIndex) // need to make a new array
|
||||
{
|
||||
arr = new List<T>();
|
||||
expandedList.Add(arr);
|
||||
}
|
||||
else // use existing array
|
||||
{
|
||||
arr = expandedList[arrayIndex];
|
||||
}
|
||||
arr.Add(val);
|
||||
}
|
||||
return (++Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the item at the specified index
|
||||
/// </summary>
|
||||
/// <param name="index">Index of the item to return</param>
|
||||
/// <returns>The item at the index specified</returns>
|
||||
public T GetItem(long index)
|
||||
{
|
||||
T val = default(T);
|
||||
|
||||
if (Count <= int.MaxValue)
|
||||
{
|
||||
int i32Index = Convert.ToInt32(index);
|
||||
val = shortList[i32Index];
|
||||
}
|
||||
else
|
||||
{
|
||||
int iArray32Index = (int) (Count/int.MaxValue);
|
||||
if (expandedList.Count > iArray32Index)
|
||||
{
|
||||
List<T> arr = expandedList[iArray32Index];
|
||||
|
||||
int i32Index = (int) (Count%int.MaxValue);
|
||||
if (arr.Count > i32Index)
|
||||
{
|
||||
val = arr[i32Index];
|
||||
}
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes an item at the specified location and shifts all the items after the provided
|
||||
/// index up by one.
|
||||
/// </summary>
|
||||
/// <param name="index">The index to remove from the list</param>
|
||||
public void RemoveAt(long index)
|
||||
{
|
||||
if (Count <= int.MaxValue)
|
||||
{
|
||||
int iArray32MemberIndex = Convert.ToInt32(index); // 0 based
|
||||
shortList.RemoveAt(iArray32MemberIndex);
|
||||
}
|
||||
else // handle the case of multiple arrays
|
||||
{
|
||||
// find out which array it is in
|
||||
int arrayIndex = (int) (index/int.MaxValue);
|
||||
List<T> arr = expandedList[arrayIndex];
|
||||
|
||||
// find out index into this array
|
||||
int iArray32MemberIndex = (int) (index%int.MaxValue);
|
||||
arr.RemoveAt(iArray32MemberIndex);
|
||||
|
||||
// now shift members of the array back one
|
||||
int iArray32TotalIndex = (int) (Count/Int32.MaxValue);
|
||||
for (int i = arrayIndex + 1; i < iArray32TotalIndex; i++)
|
||||
{
|
||||
List<T> arr1 = expandedList[i - 1];
|
||||
List<T> arr2 = expandedList[i];
|
||||
|
||||
arr1.Add(arr2[int.MaxValue - 1]);
|
||||
arr2.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
--Count;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerable<object> Implementation
|
||||
|
||||
/// <summary>
|
||||
/// Returns a generic enumerator for enumeration of this LongList
|
||||
/// </summary>
|
||||
/// <returns>Enumerator for LongList</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return new LongListEnumerator<T>(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator for enumeration of this LongList
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public class LongListEnumerator<TEt> : IEnumerator<TEt>
|
||||
{
|
||||
#region Member Variables
|
||||
|
||||
/// <summary>
|
||||
/// The index into the list of the item that is the current item
|
||||
/// </summary>
|
||||
private long index;
|
||||
|
||||
/// <summary>
|
||||
/// The current list that we're iterating over.
|
||||
/// </summary>
|
||||
private readonly LongList<TEt> localList;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new enumerator for a given LongList
|
||||
/// </summary>
|
||||
/// <param name="list">The list to enumerate</param>
|
||||
public LongListEnumerator(LongList<TEt> list)
|
||||
{
|
||||
localList = list;
|
||||
index = 0;
|
||||
Current = default(TEt);
|
||||
}
|
||||
|
||||
#region IEnumerator Implementation
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current item in the enumeration
|
||||
/// </summary>
|
||||
public TEt Current { get; private set; }
|
||||
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get { return Current; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves to the next item in the list we're iterating over
|
||||
/// </summary>
|
||||
/// <returns>Whether or not the move was successful</returns>
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (index < localList.Count)
|
||||
{
|
||||
Current = localList[index];
|
||||
index++;
|
||||
return true;
|
||||
}
|
||||
Current = default(TEt);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the enumeration
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
index = 0;
|
||||
Current = default(TEt);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposal method. Does nothing.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user