using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; using System.Text; using CYQ.Data.Tool; namespace CYQ.Data.Cache { /// /// Redis client main class. /// Use the static methods Setup and GetInstance to setup and get an instance of the client for use. /// 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(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(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(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(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 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 /// /// 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. /// public Dictionary> Stats() { Dictionary> results = new Dictionary>(); foreach (KeyValuePair item in hostServer.HostList) { results.Add(item.Key, stats(item.Value)); } return results; } private Dictionary stats(HostNode pool) { if (pool == null) { return null; } Dictionary dic = new Dictionary(); 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 } }