Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit cc6f1974ae4e94c0a71f37c94f3d194cf0f96298 Karl Seguin committed Nov 4, 2011
21 .gitignore
@@ -0,0 +1,21 @@
+TestResult.xml
+Tests.VisualState.xml
+[Bb]in
+[Oo]bj
+[Rr]elease
+[Dd]ebug
+*.bak
+*.manifest
+*.exe
+*.dll
+*.pdb
+*.cache
+*.suo
+*.orig
+*.user
+.svn
+_ReSharper*
+.DS_Store
+*.usertasks
+*.userprefs
+Metsys.Redis.Console
42 Metsys.Redis.sln
@@ -0,0 +1,42 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Metsys.Redis", "Metsys.Redis\Metsys.Redis.csproj", "{C050F51C-8CAC-4E10-A215-AE155F67EA02}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Metsys.Redis.Console", "Metsys.Redis.Console\Metsys.Redis.Console.csproj", "{B28FB5AB-98D9-4B5B-A8F6-E39BBCB64EA4}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|Mixed Platforms = Debug|Mixed Platforms
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|Mixed Platforms = Release|Mixed Platforms
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C050F51C-8CAC-4E10-A215-AE155F67EA02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C050F51C-8CAC-4E10-A215-AE155F67EA02}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C050F51C-8CAC-4E10-A215-AE155F67EA02}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {C050F51C-8CAC-4E10-A215-AE155F67EA02}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {C050F51C-8CAC-4E10-A215-AE155F67EA02}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C050F51C-8CAC-4E10-A215-AE155F67EA02}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C050F51C-8CAC-4E10-A215-AE155F67EA02}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C050F51C-8CAC-4E10-A215-AE155F67EA02}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {C050F51C-8CAC-4E10-A215-AE155F67EA02}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {C050F51C-8CAC-4E10-A215-AE155F67EA02}.Release|x86.ActiveCfg = Release|Any CPU
+ {B28FB5AB-98D9-4B5B-A8F6-E39BBCB64EA4}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {B28FB5AB-98D9-4B5B-A8F6-E39BBCB64EA4}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+ {B28FB5AB-98D9-4B5B-A8F6-E39BBCB64EA4}.Debug|Mixed Platforms.Build.0 = Debug|x86
+ {B28FB5AB-98D9-4B5B-A8F6-E39BBCB64EA4}.Debug|x86.ActiveCfg = Debug|x86
+ {B28FB5AB-98D9-4B5B-A8F6-E39BBCB64EA4}.Debug|x86.Build.0 = Debug|x86
+ {B28FB5AB-98D9-4B5B-A8F6-E39BBCB64EA4}.Release|Any CPU.ActiveCfg = Release|x86
+ {B28FB5AB-98D9-4B5B-A8F6-E39BBCB64EA4}.Release|Mixed Platforms.ActiveCfg = Release|x86
+ {B28FB5AB-98D9-4B5B-A8F6-E39BBCB64EA4}.Release|Mixed Platforms.Build.0 = Release|x86
+ {B28FB5AB-98D9-4B5B-A8F6-E39BBCB64EA4}.Release|x86.ActiveCfg = Release|x86
+ {B28FB5AB-98D9-4B5B-A8F6-E39BBCB64EA4}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
18 Metsys.Redis/Configuration.cs
@@ -0,0 +1,18 @@
+namespace Metsys.Redis
+{
+ public interface IConfiguration
+ {
+ Configuration ConnectTo(string host, int port);
+ }
+
+ public class Configuration : IConfiguration
+ {
+ public ConnectionInfo Server { get; private set; }
+
+ public Configuration ConnectTo(string host, int port)
+ {
+ Server = new ConnectionInfo(host, port);
+ return this;
+ }
+ }
+}
71 Metsys.Redis/Connections/Connection.cs
@@ -0,0 +1,71 @@
+using System;
+using System.IO;
+using System.Net.Sockets;
+
+namespace Metsys.Redis
+{
+ public interface IConnection : IDisposable
+ {
+ void Send(byte[] data, int length);
+ Stream GetStream();
+ DateTime Created { get; }
+ }
+
+ public class Connection : IConnection
+ {
+ private bool _disposed;
+ private readonly DateTime _created;
+ private readonly TcpClient _client;
+ private readonly NetworkStream _stream;
+
+ public DateTime Created
+ {
+ get { return _created; }
+ }
+
+ public Connection(ConnectionInfo connectionInfo)
+ {
+ _client = new TcpClient
+ {
+ NoDelay = true,
+ ReceiveTimeout = 10000,
+ SendTimeout = 10000
+ };
+ _client.Connect(connectionInfo.Host, connectionInfo.Port);
+ _stream = _client.GetStream();
+ _created = DateTime.Now;
+ }
+
+ public void Send(byte[] data, int length)
+ {
+ _stream.Write(data, 0, length);
+ }
+
+ public void BeginSend(byte[] data, int length)
+ {
+ _stream.Write(data, 0, length);
+ }
+
+
+ public Stream GetStream()
+ {
+ return _stream;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed) { return; }
+ _client.Close();
+ _disposed = true;
+ }
+
+ ~Connection()
+ {
+ Dispose(false);
+ }
+ }
+}
15 Metsys.Redis/Connections/ConnectionInfo.cs
@@ -0,0 +1,15 @@
+namespace Metsys.Redis
+{
+ public class ConnectionInfo
+ {
+ //if you don't get this, you don't get me
+ public readonly string Host;
+ public readonly int Port;
+
+ public ConnectionInfo(string host, int port)
+ {
+ Host = host;
+ Port = port;
+ }
+ }
+}
111 Metsys.Redis/Connections/ConnectionPool.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Metsys.Redis
+{
+ public class ConnectionPool
+ {
+ private const int _poolSize = 5;
+ private const int _maximumPoolSize = 10;
+ private readonly object _lock = new object();
+ private readonly ConnectionInfo _connectionInfo;
+ private readonly Queue<IConnection> _freeConnections = new Queue<IConnection>();
+ private readonly List<IConnection> _invalidConnections = new List<IConnection>();
+ private volatile int _connectionsInUse;
+ private Timer _timer;
+
+ public ConnectionPool(ConnectionInfo connectionInfo)
+ {
+ _connectionInfo = connectionInfo;
+ _connectionsInUse = 0;
+ _timer = new Timer(o => Cleanup(), null, 30000, 30000);
+ }
+
+ public IConnection CheckOut()
+ {
+ lock (_lock)
+ {
+ if (_freeConnections.Count > 0)
+ {
+ Interlocked.Increment(ref _connectionsInUse);
+ return _freeConnections.Dequeue();
+ }
+ if (_connectionsInUse >= _maximumPoolSize)
+ {
+ if (!Monitor.Wait(_lock, 10000))
+ {
+ throw new RedisException("Connection timeout trying to get connection from connection pool");
+ }
+ return CheckOut();
+ }
+ }
+
+ Interlocked.Increment(ref _connectionsInUse);
+ return new Connection(_connectionInfo);
+ }
+
+ public void CheckIn(IConnection connection)
+ {
+ if (!IsAlive(connection))
+ {
+ _invalidConnections.Add(connection);
+ Interlocked.Decrement(ref _connectionsInUse);
+ return;
+ }
+ lock (_lock)
+ {
+ _freeConnections.Enqueue(connection);
+ Interlocked.Decrement(ref _connectionsInUse);
+ Monitor.Pulse(_lock);
+ }
+ }
+
+ public void Cleanup()
+ {
+ CheckFreeConnectionsAlive();
+ DisposeInvalidConnections();
+ }
+
+ private void CheckFreeConnectionsAlive()
+ {
+ lock (_lock)
+ {
+ var freeConnections = _freeConnections.ToArray();
+ _freeConnections.Clear();
+
+ foreach (var connection in freeConnections)
+ {
+ if (IsAlive(connection) && _freeConnections.Count < _poolSize)
+ {
+ _freeConnections.Enqueue(connection);
+ }
+ else
+ {
+ _invalidConnections.Add(connection);
+ }
+ }
+ }
+ }
+
+ private void DisposeInvalidConnections()
+ {
+ IConnection[] invalidConnections;
+ lock (_lock)
+ {
+ invalidConnections = _invalidConnections.ToArray();
+ _invalidConnections.Clear();
+ }
+
+ foreach (var invalidConnection in invalidConnections)
+ {
+ invalidConnection.Dispose();
+ }
+ }
+
+ private static bool IsAlive(IConnection connection)
+ {
+ return DateTime.Now.Subtract(connection.Created).TotalMinutes < 10;
+ }
+ }
+}
11 Metsys.Redis/IRedis.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Metsys.Redis
+{
+ public interface IRedis : IDisposable
+ {
+ long Incr(string key);
+ long IncrBy(string key, int value);
+ long Del(string key);
+ }
+}
63 Metsys.Redis/Metsys.Redis.csproj
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{C050F51C-8CAC-4E10-A215-AE155F67EA02}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Metsys.Redis</RootNamespace>
+ <AssemblyName>Metsys.Redis</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <TargetFrameworkProfile />
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <PlatformTarget>x64</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Configuration.cs" />
+ <Compile Include="Connections\Connection.cs" />
+ <Compile Include="Connections\ConnectionInfo.cs" />
+ <Compile Include="Connections\ConnectionPool.cs" />
+ <Compile Include="Pool.cs" />
+ <Compile Include="IRedis.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Protocol\Encoding.cs" />
+ <Compile Include="Protocol\Reader.cs" />
+ <Compile Include="Protocol\WriteContext.cs" />
+ <Compile Include="Protocol\Writer.cs" />
+ <Compile Include="Redis.cs" />
+ <Compile Include="RedisException.cs" />
+ <Compile Include="RedisManager.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
35 Metsys.Redis/Pool.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Concurrent;
+
+namespace Metsys.Redis
+{
+ public class Pool<T>
+ {
+ private readonly int _count;
+ private readonly ConcurrentQueue<T> _pool;
+ private readonly Func<Pool<T>, T> _create;
+
+ public Pool(int count, Func<Pool<T>, T> create)
+ {
+ _count = count;
+ _create = create;
+ _pool = new ConcurrentQueue<T>();
+ for (var i = 0; i < count; ++i)
+ {
+ _pool.Enqueue(create(this));
+ }
+ }
+ public T CheckOut()
+ {
+ T t;
+ return _pool.TryDequeue(out t) ? t : _create(this);
+ }
+ public void CheckIn(T value)
+ {
+ if (_pool.Count < _count)
+ {
+ _pool.Enqueue(value);
+ }
+ }
+ }
+}
15 Metsys.Redis/Properties/AssemblyInfo.cs
@@ -0,0 +1,15 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Metsys.Redis")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Metsys.Redis")]
+[assembly: AssemblyCopyright("Copyright © 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+[assembly: Guid("ea13c935-20c7-4c75-953c-3eaa90669a73")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
17 Metsys.Redis/Protocol/Encoding.cs
@@ -0,0 +1,17 @@
+namespace Metsys.Redis
+{
+ public class Encoding
+ {
+ private static readonly System.Text.Encoding _encoder = System.Text.Encoding.UTF8;
+
+ public static int GetBytes(string value, int index, int length, byte[] buffer, int offset)
+ {
+ return _encoder.GetBytes(value, 0, value.Length, buffer, offset);
+ }
+
+ public static byte[] GetBytes(string value)
+ {
+ return _encoder.GetBytes(value);
+ }
+ }
+}
57 Metsys.Redis/Protocol/Reader.cs
@@ -0,0 +1,57 @@
+using System.IO;
+using System.Text;
+
+namespace Metsys.Redis
+{
+ public class Reader
+ {
+ private const byte _integerReply = (byte)':';
+ private const byte _errorReply = (byte)'-';
+
+ public static long Integer(Stream stream)
+ {
+ AssertReplyKind(_integerReply, stream);
+
+ const char zero = '0';
+ var negative = false;
+ var value = 0L;
+
+ var b = stream.ReadByte();
+ if (b == '-') { negative = true; }
+ else { value = b - zero; }
+
+ while ((b = stream.ReadByte()) != -1 && b != '\r')
+ {
+ value = value*10 + (b - zero);
+ }
+ stream.ReadByte(); // \n
+ return negative ? -value : value;
+ }
+
+ private static void AssertReplyKind(byte type, Stream stream)
+ {
+ var b = stream.ReadByte();
+ if (b == type) { return; }
+
+ if (b == _errorReply)
+ {
+ throw new RedisException(ReadLine(stream));
+ }
+ throw new RedisException(string.Format("Expecting a reply of type '{0}' but got '{1}'", (char)type, (char)b));
+ }
+
+ private static string ReadLine(Stream stream)
+ {
+ int b;
+ var sb = new StringBuilder(100);
+ while ((b = stream.ReadByte()) != -1 && b != '\r')
+ {
+ sb.Append((char)b);
+ }
+ stream.ReadByte(); // \n
+ return sb.ToString();
+ }
+
+
+ }
+}
62 Metsys.Redis/Protocol/WriteContext.cs
@@ -0,0 +1,62 @@
+using System;
+
+namespace Metsys.Redis
+{
+ public class WriteContext : IDisposable
+ {
+ private static readonly Pool<byte[]> _smallBuffer = new Pool<byte[]>(1000, p => new byte[250]);
+ private byte[] _buffer;
+ private bool _fromPool;
+ private int _length;
+ private readonly Pool<WriteContext> _parentPool;
+
+ public byte[] Buffer
+ {
+ get { return _buffer; }
+ }
+
+ public int Length
+ {
+ get { return _length; }
+ }
+
+ public WriteContext(Pool<WriteContext> parentPool)
+ {
+ _parentPool = parentPool;
+ }
+
+ public void SetLength(int length)
+ {
+ _length = length;
+ if (length < 250)
+ {
+ _buffer = _smallBuffer.CheckOut();
+ _fromPool = true;
+ }
+ else
+ {
+ _fromPool = false;
+ _buffer = new byte[length];
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposing || _buffer == null || !_fromPool) { return; }
+ _smallBuffer.CheckIn(_buffer);
+ _buffer = null;
+ _parentPool.CheckIn(this);
+ }
+
+ ~WriteContext()
+ {
+ Dispose(false);
+ }
+
+
+ }
+}
86 Metsys.Redis/Protocol/Writer.cs
@@ -0,0 +1,86 @@
+using System;
+
+namespace Metsys.Redis
+{
+ public class Writer
+ {
+ private static readonly Pool<WriteContext> _contextPool = new Pool<WriteContext>(500, p => new WriteContext(p));
+ private const byte _argumentCountMarker = (byte)'*';
+ private const byte _argumentBytesMarker = (byte)'$';
+
+ public static WriteContext Serialize(byte[] command, params object[] parameters)
+ {
+ var parameterValues = (parameters.Length + 1).ToString();
+ var commandValue = command.Length.ToString();
+
+ var length = 8 + parameterValues.Length + commandValue.Length + command.Length;
+
+ foreach (var parameter in parameters)
+ {
+ length += GetLength(parameter);
+ }
+
+ var context = _contextPool.CheckOut();
+ context.SetLength(length);
+ var buffer = context.Buffer;
+ var offset = 0;
+ offset = WriteString(buffer, offset, parameterValues, _argumentCountMarker);
+ offset = WriteString(buffer, offset, commandValue, _argumentBytesMarker);
+ offset = WriteBytes(buffer, offset, command, command.Length);
+
+ foreach(var parameter in parameters)
+ {
+ offset = WriteValue(buffer, offset, parameter);
+ }
+ return context;
+ }
+
+ private static int WriteString(byte[] buffer, int offset, string value, byte marker)
+ {
+ buffer[offset] = marker;
+ return WriteString(buffer, offset + 1, value);
+ }
+
+ private static int WriteString(byte[] buffer, int offset, string value)
+ {
+ offset += Encoding.GetBytes(value, 0, value.Length, buffer, offset);
+ return WriteLineTerminator(buffer, offset);
+ }
+
+ private static int WriteValue(byte[] buffer, int offset, object value)
+ {
+ if (value is string)
+ {
+ var v = (string)value;
+ offset = WriteString(buffer, offset, v.Length.ToString(), _argumentBytesMarker);
+ return WriteString(buffer, offset, v);
+ }
+ else
+ {
+ var v = (byte[]) value;
+ var length = v.Length;
+ offset = WriteString(buffer, offset, length.ToString(), _argumentBytesMarker);
+ return WriteBytes(buffer, offset, v, length);
+ }
+ }
+
+ private static int WriteBytes(byte[] buffer, int offset, byte[] value, int length)
+ {
+ Buffer.BlockCopy(value, 0, buffer, offset, length);
+ return WriteLineTerminator(buffer, offset + length);
+ }
+
+ private static int WriteLineTerminator(byte[] buffer, int offset)
+ {
+ buffer[offset] = (byte) '\r';
+ buffer[offset+1] = (byte) '\n';
+ return offset + 2;
+ }
+
+ private static int GetLength(object value)
+ {
+ var valueLength = value is string ? ((string) value).Length : ((byte[])value).Length;
+ return 5 + valueLength + valueLength.ToString().Length;
+ }
+ }
+}
54 Metsys.Redis/Redis.cs
@@ -0,0 +1,54 @@
+using System;
+using System.IO;
+
+namespace Metsys.Redis
+{
+ public class Redis : IRedis
+ {
+ private readonly RedisManager _manager;
+
+ public IConnection Connection { get; private set; }
+
+ internal Redis(RedisManager manager)
+ {
+ _manager = manager;
+ }
+
+ private static readonly byte[] _incrCommand = Encoding.GetBytes("INCR");
+ public long Incr(string key)
+ {
+ return Send(Writer.Serialize(_incrCommand, key), Reader.Integer);
+ }
+
+ private static readonly byte[] _incrByCommand = Encoding.GetBytes("INCRBY");
+ public long IncrBy(string key, int value)
+ {
+ return Send(Writer.Serialize(_incrByCommand, key, value.ToString()), Reader.Integer);
+ }
+
+ private static readonly byte[] _delCommand = Encoding.GetBytes("DEL");
+ public long Del(string key)
+ {
+ return Send(Writer.Serialize(_delCommand, key), Reader.Integer);
+ }
+
+ public T Send<T>(WriteContext context, Func<Stream, T> callback)
+ {
+ if (Connection == null)
+ {
+ Connection = _manager.GetConnection();
+ }
+ using (context)
+ {
+ Connection.Send(context.Buffer, context.Length);
+ return callback(Connection.GetStream());
+ }
+ }
+
+ public void Dispose()
+ {
+ _manager.CheckIn(this);
+ Connection = null;
+ }
+ }
+}
9 Metsys.Redis/RedisException.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Metsys.Redis
+{
+ public class RedisException : Exception
+ {
+ public RedisException(string message) : base(message) {}
+ }
+}
42 Metsys.Redis/RedisManager.cs
@@ -0,0 +1,42 @@
+using System;
+
+namespace Metsys.Redis
+{
+ public interface IRedisManager
+ {
+ IRedis Redis();
+ }
+
+ public class RedisManager : IRedisManager
+ {
+ private ConnectionPool _connectionPool;
+ private Pool<Redis> _redisPool;
+ private readonly Configuration _configuration = new Configuration();
+
+ public static IRedisManager Configure(Action<IConfiguration> action)
+ {
+ var manager = new RedisManager();
+ action(manager._configuration);
+ manager._connectionPool = new ConnectionPool(manager._configuration.Server);
+ manager._redisPool = new Pool<Redis>(25, p => new Redis(manager));
+ return manager;
+ }
+
+ public IRedis Redis()
+ {
+ return _redisPool.CheckOut();
+ }
+
+ public IConnection GetConnection()
+ {
+ return _connectionPool.CheckOut();
+ }
+
+ public void CheckIn(Redis redis)
+ {
+ var connection = redis.Connection;
+ if (connection != null) {_connectionPool.CheckIn(connection);}
+ _redisPool.CheckIn(redis);
+ }
+ }
+}

0 comments on commit cc6f197

Please sign in to comment.