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¡¢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);//ĬÈÏ·ÖÉ¢ÔÚ16¸öDBÖС£
|
||
//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
|
||
|
||
|
||
}
|
||
} |