mirror of https://github.com/SixLabors/ImageSharp
Browse Source
Cache is now purely file based. Very fast! Former-commit-id: 6880348d89c725fa1e7a20223fe10eb5fdb72f9daf/merge-core
18 changed files with 230 additions and 828 deletions
@ -0,0 +1,6 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<configuration> |
|||
<solution> |
|||
<add key="disableSourceControlIntegration" value="true" /> |
|||
</solution> |
|||
</configuration> |
|||
@ -0,0 +1 @@ |
|||
8f613402956f9802681f150b1cb51f8400eb628e |
|||
@ -0,0 +1,136 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<PropertyGroup> |
|||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir> |
|||
|
|||
<!-- Enable the restore command to run before builds --> |
|||
<RestorePackages Condition=" '$(RestorePackages)' == '' ">false</RestorePackages> |
|||
|
|||
<!-- Property that enables building a package from a project --> |
|||
<BuildPackage Condition=" '$(BuildPackage)' == '' ">false</BuildPackage> |
|||
|
|||
<!-- Determines if package restore consent is required to restore packages --> |
|||
<RequireRestoreConsent Condition=" '$(RequireRestoreConsent)' != 'false' ">true</RequireRestoreConsent> |
|||
|
|||
<!-- Download NuGet.exe if it does not already exist --> |
|||
<DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">false</DownloadNuGetExe> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup Condition=" '$(PackageSources)' == '' "> |
|||
<!-- Package sources used to restore packages. By default, registered sources under %APPDATA%\NuGet\NuGet.Config will be used --> |
|||
<!-- The official NuGet package source (https://www.nuget.org/api/v2/) will be excluded if package sources are specified and it does not appear in the list --> |
|||
<!-- |
|||
<PackageSource Include="https://www.nuget.org/api/v2/" /> |
|||
<PackageSource Include="https://my-nuget-source/nuget/" /> |
|||
--> |
|||
</ItemGroup> |
|||
|
|||
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT'"> |
|||
<!-- Windows specific commands --> |
|||
<NuGetToolsPath>$([System.IO.Path]::Combine($(SolutionDir), ".nuget"))</NuGetToolsPath> |
|||
<PackagesConfig>$([System.IO.Path]::Combine($(ProjectDir), "packages.config"))</PackagesConfig> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition=" '$(OS)' != 'Windows_NT'"> |
|||
<!-- We need to launch nuget.exe with the mono command if we're not on windows --> |
|||
<NuGetToolsPath>$(SolutionDir).nuget</NuGetToolsPath> |
|||
<PackagesConfig>packages.config</PackagesConfig> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup> |
|||
<!-- NuGet command --> |
|||
<NuGetExePath Condition=" '$(NuGetExePath)' == '' ">$(NuGetToolsPath)\NuGet.exe</NuGetExePath> |
|||
<PackageSources Condition=" $(PackageSources) == '' ">@(PackageSource)</PackageSources> |
|||
|
|||
<NuGetCommand Condition=" '$(OS)' == 'Windows_NT'">"$(NuGetExePath)"</NuGetCommand> |
|||
<NuGetCommand Condition=" '$(OS)' != 'Windows_NT' ">mono --runtime=v4.0.30319 $(NuGetExePath)</NuGetCommand> |
|||
|
|||
<PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir.Trim('\\'))</PackageOutputDir> |
|||
|
|||
<RequireConsentSwitch Condition=" $(RequireRestoreConsent) == 'true' ">-RequireConsent</RequireConsentSwitch> |
|||
<NonInteractiveSwitch Condition=" '$(VisualStudioVersion)' != '' AND '$(OS)' == 'Windows_NT' ">-NonInteractive</NonInteractiveSwitch> |
|||
|
|||
<PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT'">"$(SolutionDir) "</PaddedSolutionDir> |
|||
<PaddedSolutionDir Condition=" '$(OS)' != 'Windows_NT' ">"$(SolutionDir)"</PaddedSolutionDir> |
|||
|
|||
<!-- Commands --> |
|||
<RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)</RestoreCommand> |
|||
<BuildCommand>$(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols</BuildCommand> |
|||
|
|||
<!-- We need to ensure packages are restored prior to assembly resolve --> |
|||
<BuildDependsOn Condition="$(RestorePackages) == 'true'"> |
|||
RestorePackages; |
|||
$(BuildDependsOn); |
|||
</BuildDependsOn> |
|||
|
|||
<!-- Make the build depend on restore packages --> |
|||
<BuildDependsOn Condition="$(BuildPackage) == 'true'"> |
|||
$(BuildDependsOn); |
|||
BuildPackage; |
|||
</BuildDependsOn> |
|||
</PropertyGroup> |
|||
|
|||
<Target Name="CheckPrerequisites"> |
|||
<!-- Raise an error if we're unable to locate nuget.exe --> |
|||
<Error Condition="'$(DownloadNuGetExe)' != 'true' AND !Exists('$(NuGetExePath)')" Text="Unable to locate '$(NuGetExePath)'" /> |
|||
<!-- |
|||
Take advantage of MsBuild's build dependency tracking to make sure that we only ever download nuget.exe once. |
|||
This effectively acts as a lock that makes sure that the download operation will only happen once and all |
|||
parallel builds will have to wait for it to complete. |
|||
--> |
|||
<MsBuild Targets="_DownloadNuGet" Projects="$(MSBuildThisFileFullPath)" Properties="Configuration=NOT_IMPORTANT;DownloadNuGetExe=$(DownloadNuGetExe)" /> |
|||
</Target> |
|||
|
|||
<Target Name="_DownloadNuGet"> |
|||
<DownloadNuGet OutputFilename="$(NuGetExePath)" Condition=" '$(DownloadNuGetExe)' == 'true' AND !Exists('$(NuGetExePath)')" /> |
|||
</Target> |
|||
|
|||
<Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites"> |
|||
<Exec Command="$(RestoreCommand)" |
|||
Condition="'$(OS)' != 'Windows_NT' And Exists('$(PackagesConfig)')" /> |
|||
|
|||
<Exec Command="$(RestoreCommand)" |
|||
LogStandardErrorAsError="true" |
|||
Condition="'$(OS)' == 'Windows_NT' And Exists('$(PackagesConfig)')" /> |
|||
</Target> |
|||
|
|||
<Target Name="BuildPackage" DependsOnTargets="CheckPrerequisites"> |
|||
<Exec Command="$(BuildCommand)" |
|||
Condition=" '$(OS)' != 'Windows_NT' " /> |
|||
|
|||
<Exec Command="$(BuildCommand)" |
|||
LogStandardErrorAsError="true" |
|||
Condition=" '$(OS)' == 'Windows_NT' " /> |
|||
</Target> |
|||
|
|||
<UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll"> |
|||
<ParameterGroup> |
|||
<OutputFilename ParameterType="System.String" Required="true" /> |
|||
</ParameterGroup> |
|||
<Task> |
|||
<Reference Include="System.Core" /> |
|||
<Using Namespace="System" /> |
|||
<Using Namespace="System.IO" /> |
|||
<Using Namespace="System.Net" /> |
|||
<Using Namespace="Microsoft.Build.Framework" /> |
|||
<Using Namespace="Microsoft.Build.Utilities" /> |
|||
<Code Type="Fragment" Language="cs"> |
|||
<![CDATA[ |
|||
try { |
|||
OutputFilename = Path.GetFullPath(OutputFilename); |
|||
|
|||
Log.LogMessage("Downloading latest version of NuGet.exe..."); |
|||
WebClient webClient = new WebClient(); |
|||
webClient.DownloadFile("https://www.nuget.org/nuget.exe", OutputFilename); |
|||
|
|||
return true; |
|||
} |
|||
catch (Exception ex) { |
|||
Log.LogErrorFromException(ex); |
|||
return false; |
|||
} |
|||
]]> |
|||
</Code> |
|||
</Task> |
|||
</UsingTask> |
|||
</Project> |
|||
@ -1,150 +0,0 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="SQLContext.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Provides a wrapper for the SQLite functionality.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Caching |
|||
{ |
|||
#region Using
|
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using System.Web.Hosting; |
|||
using ImageProcessor.Web.Config; |
|||
using SQLite; |
|||
#endregion
|
|||
|
|||
/// <summary>
|
|||
/// Provides a wrapper for the SQLite functionality.
|
|||
/// </summary>
|
|||
internal sealed class SQLContext |
|||
{ |
|||
#region Fields
|
|||
/// <summary>
|
|||
/// The default path for cached folders on the server.
|
|||
/// </summary>
|
|||
private static readonly string VirtualCachePath = ImageProcessorConfig.Instance.VirtualCachePath; |
|||
|
|||
/// <summary>
|
|||
/// The cached index location.
|
|||
/// </summary>
|
|||
private static readonly string IndexLocation = Path.Combine(HostingEnvironment.MapPath(VirtualCachePath), "cache.db"); |
|||
|
|||
/// <summary>
|
|||
/// The connection string.
|
|||
/// </summary>
|
|||
private static readonly string ConnectionString = IndexLocation; |
|||
#endregion
|
|||
|
|||
#region Methods
|
|||
#region Internal
|
|||
/// <summary>
|
|||
/// Creates the database if it doesn't already exist.
|
|||
/// </summary>
|
|||
internal static void CreateDatabase() |
|||
{ |
|||
try |
|||
{ |
|||
if (!File.Exists(IndexLocation)) |
|||
{ |
|||
string absolutePath = HostingEnvironment.MapPath(VirtualCachePath); |
|||
|
|||
if (absolutePath != null) |
|||
{ |
|||
DirectoryInfo directoryInfo = new DirectoryInfo(absolutePath); |
|||
|
|||
if (!directoryInfo.Exists) |
|||
{ |
|||
// Create the directory.
|
|||
Directory.CreateDirectory(absolutePath); |
|||
} |
|||
} |
|||
|
|||
using (SQLiteConnection connection = new SQLiteConnection(IndexLocation)) |
|||
{ |
|||
connection.CreateTable<CachedImage>(); |
|||
} |
|||
} |
|||
} |
|||
catch |
|||
{ |
|||
throw; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a cached image from the database.
|
|||
/// </summary>
|
|||
/// <param name="key">
|
|||
/// The key for the cached image to get.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="CachedImage"/> from the database.
|
|||
/// </returns>
|
|||
internal static async Task<CachedImage> GetImageAsync(string key) |
|||
{ |
|||
try |
|||
{ |
|||
SQLiteAsyncConnection connection = new SQLiteAsyncConnection(ConnectionString); |
|||
|
|||
return await connection.GetAsync<CachedImage>(c => c.Key == key); |
|||
} |
|||
catch |
|||
{ |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds a cached image to the database.
|
|||
/// </summary>
|
|||
/// <param name="image">
|
|||
/// The cached image to add.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The true if the addition of the cached image is added; otherwise, false.
|
|||
/// </returns>
|
|||
internal static async Task<int> AddImageAsync(CachedImage image) |
|||
{ |
|||
try |
|||
{ |
|||
SQLiteAsyncConnection connection = new SQLiteAsyncConnection(ConnectionString); |
|||
return await connection.InsertAsync(image); |
|||
} |
|||
catch |
|||
{ |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes a cached image from the database.
|
|||
/// </summary>
|
|||
/// <param name="key">
|
|||
/// The key for the cached image.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The true if the addition of the cached image is removed; otherwise, false.
|
|||
/// </returns>
|
|||
internal static async Task<int> RemoveImageAsync(string key) |
|||
{ |
|||
try |
|||
{ |
|||
SQLiteAsyncConnection connection = new SQLiteAsyncConnection(ConnectionString); |
|||
CachedImage cachedImage = await connection.GetAsync<CachedImage>(c => c.Key == key); |
|||
|
|||
return await connection.DeleteAsync(cachedImage); |
|||
} |
|||
catch |
|||
{ |
|||
return 0; |
|||
} |
|||
} |
|||
#endregion
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -1 +0,0 @@ |
|||
ce0491dcbe39702bf25fb616f76e1b149f670688 |
|||
@ -1,486 +0,0 @@ |
|||
//
|
|||
// Copyright (c) 2012 Krueger Systems, Inc.
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|||
// of this software and associated documentation files (the "Software"), to deal
|
|||
// in the Software without restriction, including without limitation the rights
|
|||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the Software is
|
|||
// furnished to do so, subject to the following conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be included in
|
|||
// all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|||
// THE SOFTWARE.
|
|||
//
|
|||
|
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Linq.Expressions; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace SQLite |
|||
{ |
|||
public partial class SQLiteAsyncConnection |
|||
{ |
|||
SQLiteConnectionString _connectionString; |
|||
|
|||
public SQLiteAsyncConnection (string databasePath, bool storeDateTimeAsTicks = false) |
|||
{ |
|||
_connectionString = new SQLiteConnectionString (databasePath, storeDateTimeAsTicks); |
|||
} |
|||
|
|||
SQLiteConnectionWithLock GetConnection () |
|||
{ |
|||
return SQLiteConnectionPool.Shared.GetConnection (_connectionString); |
|||
} |
|||
|
|||
public Task<CreateTablesResult> CreateTableAsync<T> () |
|||
where T : new () |
|||
{ |
|||
return CreateTablesAsync (typeof (T)); |
|||
} |
|||
|
|||
public Task<CreateTablesResult> CreateTablesAsync<T, T2> () |
|||
where T : new () |
|||
where T2 : new () |
|||
{ |
|||
return CreateTablesAsync (typeof (T), typeof (T2)); |
|||
} |
|||
|
|||
public Task<CreateTablesResult> CreateTablesAsync<T, T2, T3> () |
|||
where T : new () |
|||
where T2 : new () |
|||
where T3 : new () |
|||
{ |
|||
return CreateTablesAsync (typeof (T), typeof (T2), typeof (T3)); |
|||
} |
|||
|
|||
public Task<CreateTablesResult> CreateTablesAsync<T, T2, T3, T4> () |
|||
where T : new () |
|||
where T2 : new () |
|||
where T3 : new () |
|||
where T4 : new () |
|||
{ |
|||
return CreateTablesAsync (typeof (T), typeof (T2), typeof (T3), typeof (T4)); |
|||
} |
|||
|
|||
public Task<CreateTablesResult> CreateTablesAsync<T, T2, T3, T4, T5> () |
|||
where T : new () |
|||
where T2 : new () |
|||
where T3 : new () |
|||
where T4 : new () |
|||
where T5 : new () |
|||
{ |
|||
return CreateTablesAsync (typeof (T), typeof (T2), typeof (T3), typeof (T4), typeof (T5)); |
|||
} |
|||
|
|||
public Task<CreateTablesResult> CreateTablesAsync (params Type[] types) |
|||
{ |
|||
return Task.Factory.StartNew (() => { |
|||
CreateTablesResult result = new CreateTablesResult (); |
|||
var conn = GetConnection (); |
|||
using (conn.Lock ()) { |
|||
foreach (Type type in types) { |
|||
int aResult = conn.CreateTable (type); |
|||
result.Results[type] = aResult; |
|||
} |
|||
} |
|||
return result; |
|||
}); |
|||
} |
|||
|
|||
public Task<int> DropTableAsync<T> () |
|||
where T : new () |
|||
{ |
|||
return Task.Factory.StartNew (() => { |
|||
var conn = GetConnection (); |
|||
using (conn.Lock ()) { |
|||
return conn.DropTable<T> (); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task<int> InsertAsync (object item) |
|||
{ |
|||
return Task.Factory.StartNew (() => { |
|||
var conn = GetConnection (); |
|||
using (conn.Lock ()) { |
|||
return conn.Insert (item); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task<int> UpdateAsync (object item) |
|||
{ |
|||
return Task.Factory.StartNew (() => { |
|||
var conn = GetConnection (); |
|||
using (conn.Lock ()) { |
|||
return conn.Update (item); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task<int> DeleteAsync (object item) |
|||
{ |
|||
return Task.Factory.StartNew (() => { |
|||
var conn = GetConnection (); |
|||
using (conn.Lock ()) { |
|||
return conn.Delete (item); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task<T> GetAsync<T>(object pk) |
|||
where T : new() |
|||
{ |
|||
return Task.Factory.StartNew(() => |
|||
{ |
|||
var conn = GetConnection(); |
|||
using (conn.Lock()) |
|||
{ |
|||
return conn.Get<T>(pk); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task<T> FindAsync<T> (object pk) |
|||
where T : new () |
|||
{ |
|||
return Task.Factory.StartNew (() => { |
|||
var conn = GetConnection (); |
|||
using (conn.Lock ()) { |
|||
return conn.Find<T> (pk); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task<T> GetAsync<T> (Expression<Func<T, bool>> predicate) |
|||
where T : new() |
|||
{ |
|||
return Task.Factory.StartNew(() => |
|||
{ |
|||
var conn = GetConnection(); |
|||
using (conn.Lock()) |
|||
{ |
|||
return conn.Get<T> (predicate); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task<T> FindAsync<T> (Expression<Func<T, bool>> predicate) |
|||
where T : new () |
|||
{ |
|||
return Task.Factory.StartNew (() => { |
|||
var conn = GetConnection (); |
|||
using (conn.Lock ()) { |
|||
return conn.Find<T> (predicate); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task<int> ExecuteAsync (string query, params object[] args) |
|||
{ |
|||
return Task<int>.Factory.StartNew (() => { |
|||
var conn = GetConnection (); |
|||
using (conn.Lock ()) { |
|||
return conn.Execute (query, args); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task<int> InsertAllAsync (IEnumerable items) |
|||
{ |
|||
return Task.Factory.StartNew (() => { |
|||
var conn = GetConnection (); |
|||
using (conn.Lock ()) { |
|||
return conn.InsertAll (items); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
[Obsolete("Will cause a deadlock if any call in action ends up in a different thread. Use RunInTransactionAsync(Action<SQLiteConnection>) instead.")] |
|||
public Task RunInTransactionAsync (Action<SQLiteAsyncConnection> action) |
|||
{ |
|||
return Task.Factory.StartNew (() => { |
|||
var conn = this.GetConnection (); |
|||
using (conn.Lock ()) { |
|||
conn.BeginTransaction (); |
|||
try { |
|||
action (this); |
|||
conn.Commit (); |
|||
} |
|||
catch (Exception) { |
|||
conn.Rollback (); |
|||
throw; |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task RunInTransactionAsync(Action<SQLiteConnection> action) |
|||
{ |
|||
return Task.Factory.StartNew(() => |
|||
{ |
|||
var conn = this.GetConnection(); |
|||
using (conn.Lock()) |
|||
{ |
|||
conn.BeginTransaction(); |
|||
try |
|||
{ |
|||
action(conn); |
|||
conn.Commit(); |
|||
} |
|||
catch (Exception) |
|||
{ |
|||
conn.Rollback(); |
|||
throw; |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public AsyncTableQuery<T> Table<T> () |
|||
where T : new () |
|||
{ |
|||
//
|
|||
// This isn't async as the underlying connection doesn't go out to the database
|
|||
// until the query is performed. The Async methods are on the query iteself.
|
|||
//
|
|||
var conn = GetConnection (); |
|||
return new AsyncTableQuery<T> (conn.Table<T> ()); |
|||
} |
|||
|
|||
public Task<T> ExecuteScalarAsync<T> (string sql, params object[] args) |
|||
{ |
|||
return Task<T>.Factory.StartNew (() => { |
|||
var conn = GetConnection (); |
|||
using (conn.Lock ()) { |
|||
var command = conn.CreateCommand (sql, args); |
|||
return command.ExecuteScalar<T> (); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task<List<T>> QueryAsync<T> (string sql, params object[] args) |
|||
where T : new () |
|||
{ |
|||
return Task<List<T>>.Factory.StartNew (() => { |
|||
var conn = GetConnection (); |
|||
using (conn.Lock ()) { |
|||
return conn.Query<T> (sql, args); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
|
|||
//
|
|||
// TODO: Bind to AsyncConnection.GetConnection instead so that delayed
|
|||
// execution can still work after a Pool.Reset.
|
|||
//
|
|||
public class AsyncTableQuery<T> |
|||
where T : new () |
|||
{ |
|||
TableQuery<T> _innerQuery; |
|||
|
|||
public AsyncTableQuery (TableQuery<T> innerQuery) |
|||
{ |
|||
_innerQuery = innerQuery; |
|||
} |
|||
|
|||
public AsyncTableQuery<T> Where (Expression<Func<T, bool>> predExpr) |
|||
{ |
|||
return new AsyncTableQuery<T> (_innerQuery.Where (predExpr)); |
|||
} |
|||
|
|||
public AsyncTableQuery<T> Skip (int n) |
|||
{ |
|||
return new AsyncTableQuery<T> (_innerQuery.Skip (n)); |
|||
} |
|||
|
|||
public AsyncTableQuery<T> Take (int n) |
|||
{ |
|||
return new AsyncTableQuery<T> (_innerQuery.Take (n)); |
|||
} |
|||
|
|||
public AsyncTableQuery<T> OrderBy<U> (Expression<Func<T, U>> orderExpr) |
|||
{ |
|||
return new AsyncTableQuery<T> (_innerQuery.OrderBy<U> (orderExpr)); |
|||
} |
|||
|
|||
public AsyncTableQuery<T> OrderByDescending<U> (Expression<Func<T, U>> orderExpr) |
|||
{ |
|||
return new AsyncTableQuery<T> (_innerQuery.OrderByDescending<U> (orderExpr)); |
|||
} |
|||
|
|||
public Task<List<T>> ToListAsync () |
|||
{ |
|||
return Task.Factory.StartNew (() => { |
|||
using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) { |
|||
return _innerQuery.ToList (); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task<int> CountAsync () |
|||
{ |
|||
return Task.Factory.StartNew (() => { |
|||
using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) { |
|||
return _innerQuery.Count (); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task<T> ElementAtAsync (int index) |
|||
{ |
|||
return Task.Factory.StartNew (() => { |
|||
using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) { |
|||
return _innerQuery.ElementAt (index); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task<T> FirstAsync () |
|||
{ |
|||
return Task<T>.Factory.StartNew(() => { |
|||
using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) { |
|||
return _innerQuery.First (); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Task<T> FirstOrDefaultAsync () |
|||
{ |
|||
return Task<T>.Factory.StartNew(() => { |
|||
using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) { |
|||
return _innerQuery.FirstOrDefault (); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
|
|||
public class CreateTablesResult |
|||
{ |
|||
public Dictionary<Type, int> Results { get; private set; } |
|||
|
|||
internal CreateTablesResult () |
|||
{ |
|||
this.Results = new Dictionary<Type, int> (); |
|||
} |
|||
} |
|||
|
|||
class SQLiteConnectionPool |
|||
{ |
|||
class Entry |
|||
{ |
|||
public SQLiteConnectionString ConnectionString { get; private set; } |
|||
public SQLiteConnectionWithLock Connection { get; private set; } |
|||
|
|||
public Entry (SQLiteConnectionString connectionString) |
|||
{ |
|||
ConnectionString = connectionString; |
|||
Connection = new SQLiteConnectionWithLock (connectionString); |
|||
} |
|||
|
|||
public void OnApplicationSuspended () |
|||
{ |
|||
Connection.Dispose (); |
|||
Connection = null; |
|||
} |
|||
} |
|||
|
|||
readonly Dictionary<string, Entry> _entries = new Dictionary<string, Entry> (); |
|||
readonly object _entriesLock = new object (); |
|||
|
|||
static readonly SQLiteConnectionPool _shared = new SQLiteConnectionPool (); |
|||
|
|||
/// <summary>
|
|||
/// Gets the singleton instance of the connection tool.
|
|||
/// </summary>
|
|||
public static SQLiteConnectionPool Shared |
|||
{ |
|||
get |
|||
{ |
|||
return _shared; |
|||
} |
|||
} |
|||
|
|||
public SQLiteConnectionWithLock GetConnection (SQLiteConnectionString connectionString) |
|||
{ |
|||
lock (_entriesLock) { |
|||
Entry entry; |
|||
string key = connectionString.ConnectionString; |
|||
|
|||
if (!_entries.TryGetValue (key, out entry)) { |
|||
entry = new Entry (connectionString); |
|||
_entries[key] = entry; |
|||
} |
|||
|
|||
return entry.Connection; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Closes all connections managed by this pool.
|
|||
/// </summary>
|
|||
public void Reset () |
|||
{ |
|||
lock (_entriesLock) { |
|||
foreach (var entry in _entries.Values) { |
|||
entry.OnApplicationSuspended (); |
|||
} |
|||
_entries.Clear (); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Call this method when the application is suspended.
|
|||
/// </summary>
|
|||
/// <remarks>Behaviour here is to close any open connections.</remarks>
|
|||
public void ApplicationSuspended () |
|||
{ |
|||
Reset (); |
|||
} |
|||
} |
|||
|
|||
class SQLiteConnectionWithLock : SQLiteConnection |
|||
{ |
|||
readonly object _lockPoint = new object (); |
|||
|
|||
public SQLiteConnectionWithLock (SQLiteConnectionString connectionString) |
|||
: base (connectionString.DatabasePath, connectionString.StoreDateTimeAsTicks) |
|||
{ |
|||
} |
|||
|
|||
public IDisposable Lock () |
|||
{ |
|||
return new LockWrapper (_lockPoint); |
|||
} |
|||
|
|||
private class LockWrapper : IDisposable |
|||
{ |
|||
object _lockPoint; |
|||
|
|||
public LockWrapper (object lockPoint) |
|||
{ |
|||
_lockPoint = lockPoint; |
|||
Monitor.Enter (_lockPoint); |
|||
} |
|||
|
|||
public void Dispose () |
|||
{ |
|||
Monitor.Exit (_lockPoint); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,5 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<packages > |
|||
<package id="Csharp-Sqlite" version="3.7.7.1" targetFramework="net40" /> |
|||
<package id="sqlite-net" version="1.0.7" targetFramework="net40" /> |
|||
</packages> |
|||
@ -1,6 +1,5 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<repositories> |
|||
<repository path="..\ImageProcessor.Web\NET4\packages.config" /> |
|||
<repository path="..\ImageProcessor.Web\NET45\packages.config" /> |
|||
<repository path="..\TestWebsites\NET45\Test_Website_NET45\packages.config" /> |
|||
</repositories> |
|||
Loading…
Reference in new issue