342 lines
11 KiB
C#
342 lines
11 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Collections.Specialized;
|
|||
|
|
using System.Globalization;
|
|||
|
|
using System.Text;
|
|||
|
|
using CYQ.Data.Tool;
|
|||
|
|
|
|||
|
|
namespace CYQ.Data.Cache
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// Redis client main class.
|
|||
|
|
/// Use the static methods Setup and GetInstance to setup and get an instance of the client for use.
|
|||
|
|
/// </summary>
|
|||
|
|
internal class RedisClient : ClientBase
|
|||
|
|
{
|
|||
|
|
#region Static fields and methods.
|
|||
|
|
private static LogAdapter logger = LogAdapter.GetLogger(typeof(RedisClient));
|
|||
|
|
|
|||
|
|
|
|||
|
|
public static RedisClient Create(string configValue)
|
|||
|
|
{
|
|||
|
|
return new RedisClient(configValue);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
private RedisClient(string configValue)
|
|||
|
|
{
|
|||
|
|
hostServer = new HostServer(CacheType.Redis, configValue);
|
|||
|
|
hostServer.OnAuthEvent += new HostServer.AuthDelegate(hostServer_OnAuthEvent);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool hostServer_OnAuthEvent(MSocket socket)
|
|||
|
|
{
|
|||
|
|
if (!Auth(socket.HostNode.Password, socket))
|
|||
|
|
{
|
|||
|
|
string err = "Auth password fail : " + socket.HostNode.Password;
|
|||
|
|
socket.HostNode.Error = err;
|
|||
|
|
Error.Throw(err);
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
|
|||
|
|
#region Set<EFBFBD><EFBFBD>Append
|
|||
|
|
|
|||
|
|
public bool Append(string key, object value, int seconds) { return Set("append", key, true, value, hash(key), seconds); }
|
|||
|
|
public bool Set(string key, object value, int seconds) { return Set("set", key, true, value, hash(key), seconds); }
|
|||
|
|
|
|||
|
|
|
|||
|
|
private bool Set(string command, string key, bool keyIsChecked, object value, uint hash, int expirySeconds)
|
|||
|
|
{
|
|||
|
|
if (!keyIsChecked)
|
|||
|
|
{
|
|||
|
|
checkKey(key);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
string result = hostServer.Execute<string>(hash, "", delegate(MSocket socket)
|
|||
|
|
{
|
|||
|
|
SerializedType type;
|
|||
|
|
byte[] bytes;
|
|||
|
|
byte[] typeBit = new byte[1];
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
bytes = Serializer.Serialize(value, out type, compressionThreshold);
|
|||
|
|
typeBit[0] = (byte)type;
|
|||
|
|
}
|
|||
|
|
catch (Exception e)
|
|||
|
|
{
|
|||
|
|
logger.Error("Error serializing object for key '" + key + "'.", e);
|
|||
|
|
return "";
|
|||
|
|
}
|
|||
|
|
// CheckDB(socket, hash);
|
|||
|
|
int db = GetDBIndex(socket, hash);
|
|||
|
|
// Console.WriteLine("Set :" + key + ":" + hash + " db." + db);
|
|||
|
|
int skipCmd = 0;
|
|||
|
|
using (RedisCommand cmd = new RedisCommand(socket))
|
|||
|
|
{
|
|||
|
|
if (db > -1)
|
|||
|
|
{
|
|||
|
|
cmd.Reset(2, "Select");
|
|||
|
|
cmd.AddKey(db.ToString());
|
|||
|
|
skipCmd++;
|
|||
|
|
}
|
|||
|
|
cmd.Reset(3, command);
|
|||
|
|
cmd.AddKey(key);
|
|||
|
|
cmd.AddValue(typeBit, bytes);
|
|||
|
|
skipCmd++;
|
|||
|
|
//cmd.Send();
|
|||
|
|
//if (db != -1)
|
|||
|
|
//{
|
|||
|
|
// string aaa = socket.ReadLine();
|
|||
|
|
//}
|
|||
|
|
//result = socket.ReadResponse();
|
|||
|
|
//if (result[0] != '-')
|
|||
|
|
//{
|
|||
|
|
if (expirySeconds > 0)
|
|||
|
|
{
|
|||
|
|
cmd.Reset(3, "EXPIRE");
|
|||
|
|
cmd.AddKey(key);
|
|||
|
|
cmd.AddKey(expirySeconds.ToString());
|
|||
|
|
skipCmd++;
|
|||
|
|
// cmd.Send();
|
|||
|
|
//result = socket.ReadResponse();
|
|||
|
|
}
|
|||
|
|
// }
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
socket.SkipToEndOfLine(skipCmd - 1);
|
|||
|
|
return socket.ReadResponse();
|
|||
|
|
|
|||
|
|
});
|
|||
|
|
return result == "+OK" || result == ":1";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Get
|
|||
|
|
public object Get(string key) { return Get("get", key, true, hash(key)); }
|
|||
|
|
|
|||
|
|
private object Get(string command, string key, bool keyIsChecked, uint hash)
|
|||
|
|
{
|
|||
|
|
if (!keyIsChecked)
|
|||
|
|
{
|
|||
|
|
checkKey(key);
|
|||
|
|
}
|
|||
|
|
object value = hostServer.Execute<object>(hash, null, delegate(MSocket socket)
|
|||
|
|
{
|
|||
|
|
int db = GetDBIndex(socket, hash);
|
|||
|
|
using (RedisCommand cmd = new RedisCommand(socket))
|
|||
|
|
{
|
|||
|
|
if (db > -1)
|
|||
|
|
{
|
|||
|
|
cmd.Reset(2, "Select");
|
|||
|
|
cmd.AddKey(db.ToString());
|
|||
|
|
}
|
|||
|
|
cmd.Reset(2, command);
|
|||
|
|
cmd.AddKey(key);
|
|||
|
|
}
|
|||
|
|
if (db > -1) { socket.SkipToEndOfLine(); }
|
|||
|
|
string result = socket.ReadResponse();
|
|||
|
|
if (!string.IsNullOrEmpty(result) && result[0] == '$')
|
|||
|
|
{
|
|||
|
|
int len = 0;
|
|||
|
|
if (int.TryParse(result.Substring(1), out len) && len > 0)
|
|||
|
|
{
|
|||
|
|
byte[] bytes = socket.ReadBytes(len);
|
|||
|
|
if (bytes.Length > 0)
|
|||
|
|
{
|
|||
|
|
byte[] data = new byte[bytes.Length - 1];
|
|||
|
|
SerializedType st = (SerializedType)bytes[0];
|
|||
|
|
Array.Copy(bytes, 1, data, 0, data.Length);
|
|||
|
|
bytes = null;
|
|||
|
|
return Serializer.DeSerialize(data, st);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
});
|
|||
|
|
return value;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Exists
|
|||
|
|
public bool ContainsKey(string key) { return ContainsKey(key, true, hash(key)); }
|
|||
|
|
|
|||
|
|
private bool ContainsKey(string key, bool keyIsChecked, uint hash)
|
|||
|
|
{
|
|||
|
|
if (!keyIsChecked)
|
|||
|
|
{
|
|||
|
|
checkKey(key);
|
|||
|
|
}
|
|||
|
|
return hostServer.Execute<bool>(hash, false, delegate(MSocket socket)
|
|||
|
|
{
|
|||
|
|
int db = GetDBIndex(socket, hash);
|
|||
|
|
//Console.WriteLine("ContainsKey :" + key + ":" + hash + " db." + db);
|
|||
|
|
using (RedisCommand cmd = new RedisCommand(socket))
|
|||
|
|
{
|
|||
|
|
if (db > -1)
|
|||
|
|
{
|
|||
|
|
cmd.Reset(2, "Select");
|
|||
|
|
cmd.AddKey(db.ToString());
|
|||
|
|
}
|
|||
|
|
cmd.Reset(2, "Exists");
|
|||
|
|
cmd.AddKey(key);
|
|||
|
|
}
|
|||
|
|
if (db > -1) { socket.SkipToEndOfLine(); }
|
|||
|
|
string result = socket.ReadResponse();
|
|||
|
|
return !result.StartsWith(":0") && !result.StartsWith("-");
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Select DB
|
|||
|
|
internal int GetDBIndex(MSocket socket, uint hash)
|
|||
|
|
{
|
|||
|
|
if (AppConfig.Cache.RedisUseDBCount > 1 || AppConfig.Cache.RedisUseDBIndex > 0)
|
|||
|
|
{
|
|||
|
|
return AppConfig.Cache.RedisUseDBIndex > 0 ? AppConfig.Cache.RedisUseDBIndex : (int)(hash % AppConfig.Cache.RedisUseDBCount);//Ĭ<>Ϸ<EFBFBD>ɢ<EFBFBD><C9A2>16<31><36>DB<44>С<EFBFBD>
|
|||
|
|
//if (socket.DB != db)
|
|||
|
|
//{
|
|||
|
|
// socket.DB = db;
|
|||
|
|
// return (int)db;
|
|||
|
|
//}
|
|||
|
|
}
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Delete
|
|||
|
|
|
|||
|
|
|
|||
|
|
public bool Delete(string key) { return Delete(key, true, hash(key), 0); }
|
|||
|
|
|
|||
|
|
private bool Delete(string key, bool keyIsChecked, uint hash, int time)
|
|||
|
|
{
|
|||
|
|
if (!keyIsChecked)
|
|||
|
|
{
|
|||
|
|
checkKey(key);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return hostServer.Execute<bool>(hash, false, delegate(MSocket socket)
|
|||
|
|
{
|
|||
|
|
int db = GetDBIndex(socket, hash);
|
|||
|
|
using (RedisCommand cmd = new RedisCommand(socket))
|
|||
|
|
{
|
|||
|
|
if (db > -1)
|
|||
|
|
{
|
|||
|
|
cmd.Reset(2, "Select");
|
|||
|
|
cmd.AddKey(db.ToString());
|
|||
|
|
}
|
|||
|
|
cmd.Reset(2, "DEL");
|
|||
|
|
cmd.AddKey(key);
|
|||
|
|
}
|
|||
|
|
if (db > -1)
|
|||
|
|
{
|
|||
|
|
socket.SkipToEndOfLine();
|
|||
|
|
}
|
|||
|
|
string result = socket.ReadResponse();
|
|||
|
|
return result.StartsWith(":1");
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Auth
|
|||
|
|
|
|||
|
|
private bool Auth(string password, MSocket socket)
|
|||
|
|
{
|
|||
|
|
if (!string.IsNullOrEmpty(password))
|
|||
|
|
{
|
|||
|
|
using (RedisCommand cmd = new RedisCommand(socket, 2, "AUTH"))
|
|||
|
|
{
|
|||
|
|
cmd.AddKey(password);
|
|||
|
|
}
|
|||
|
|
string result = socket.ReadLine();
|
|||
|
|
return result.StartsWith("+OK");
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Flush All
|
|||
|
|
|
|||
|
|
public bool FlushAll()
|
|||
|
|
{
|
|||
|
|
foreach (KeyValuePair<string, HostNode> item in hostServer.HostList)
|
|||
|
|
{
|
|||
|
|
HostNode pool = item.Value;
|
|||
|
|
hostServer.Execute(pool, delegate(MSocket socket)
|
|||
|
|
{
|
|||
|
|
using (RedisCommand cmd = new RedisCommand(socket, 1, "flushall"))
|
|||
|
|
{
|
|||
|
|
cmd.Send();
|
|||
|
|
socket.SkipToEndOfLine();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Stats
|
|||
|
|
/// <summary>
|
|||
|
|
/// This method corresponds to the "stats" command in the memcached protocol.
|
|||
|
|
/// It will send the stats command to all servers, and it will return a Dictionary for each server
|
|||
|
|
/// containing the results of the command.
|
|||
|
|
/// </summary>
|
|||
|
|
public Dictionary<string, Dictionary<string, string>> Stats()
|
|||
|
|
{
|
|||
|
|
Dictionary<string, Dictionary<string, string>> results = new Dictionary<string, Dictionary<string, string>>();
|
|||
|
|
foreach (KeyValuePair<string, HostNode> item in hostServer.HostList)
|
|||
|
|
{
|
|||
|
|
results.Add(item.Key, stats(item.Value));
|
|||
|
|
}
|
|||
|
|
return results;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private Dictionary<string, string> stats(HostNode pool)
|
|||
|
|
{
|
|||
|
|
if (pool == null)
|
|||
|
|
{
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
Dictionary<string, string> dic = new Dictionary<string, string>();
|
|||
|
|
hostServer.Execute(pool, delegate(MSocket socket)
|
|||
|
|
{
|
|||
|
|
using (RedisCommand cmd = new RedisCommand(socket, 1, "info"))
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
string result = socket.ReadResponse();
|
|||
|
|
if (!string.IsNullOrEmpty(result) && (result[0] == '$' || result == "+OK"))
|
|||
|
|
{
|
|||
|
|
string line = null;
|
|||
|
|
while (true)
|
|||
|
|
{
|
|||
|
|
line = socket.ReadLine();
|
|||
|
|
if (line == null)
|
|||
|
|
{
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
string[] s = line.Split(':');
|
|||
|
|
dic.Add(s[0], s[1]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
return dic;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|