namespace Memcached.ClientLibrary
{
using ICSharpCode.SharpZipLib.GZip;
using log4net;
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Resources;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Text.RegularExpressions;
public class MemcachedClient
{
private bool _compressEnable;
private long _compressThreshold;
private string _defaultEncoding;
private string _poolName;
private bool _primitiveAsString;//Memcached.ClientLibrary.StringMessages
private static ResourceManager _resourceManager = new ResourceManager("Memcached.ClientLibrary.StringMessages", typeof(MemcachedClient).Assembly);
private const string CLIENT_ERROR = "CLIENT_ERROR";
private const int COMPRESS_THRESH = 0x7800;
private const string DELETED = "DELETED";
private const string END = "END";
private const string ERROR = "ERROR";
private const int F_COMPRESSED = 2;
private const int F_SERIALIZED = 8;
private static ILog log = LogManager.GetLogger(typeof(MemcachedClient));
private const string NOTFOUND = "NOT_FOUND";
private const string NOTSTORED = "NOT_STORED";
private const string OK = "OK";
private const string SERVER_ERROR = "SERVER_ERROR";
private const string STATS = "STAT";
private const string STORED = "STORED";
private const string VALUE = "VALUE";
public MemcachedClient(): this("default instance")
{
}
public MemcachedClient(string name)
{
if (name != "")
{
this.Init(name);
}
else
{
this.Init();
}
}
private void Init(string key)
{
this._primitiveAsString = false;
this._compressEnable = true;
this._compressThreshold = 0x7800L;
this._defaultEncoding = "UTF-8";
this._poolName = GetLocalizedString(key);
}
public bool Add(string key, object value)
{
return this.Set("add", key, value, DateTime.MaxValue, null, this._primitiveAsString);
}
public bool Add(string key, object value, DateTime expiry)
{
return this.Set("add", key, value, expiry, null, this._primitiveAsString);
}
public bool Add(string key, object value, int hashCode)
{
return this.Set("add", key, value, DateTime.MaxValue, hashCode, this._primitiveAsString);
}
public bool Add(string key, object value, DateTime expiry, int hashCode)
{
return this.Set("add", key, value, expiry, hashCode, this._primitiveAsString);
}
public long Decrement(string key)
{
return this.IncrementOrDecrement("decr", key, 1L, null);
}
public long Decrement(string key, long inc)
{
return this.IncrementOrDecrement("decr", key, inc, null);
}
public long Decrement(string key, long inc, int hashCode)
{
return this.IncrementOrDecrement("decr", key, inc, hashCode);
}
public bool Delete(string key)
{
return this.Delete(key, null, DateTime.MaxValue);
}
public bool Delete(string key, DateTime expiry)
{
return this.Delete(key, null, expiry);
}
public bool Delete(string key, object hashCode, DateTime expiry)
{
if (key == null)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("null key delete"));
}
return false;
}
SockIO sock = SockIOPool.GetInstance(this._poolName).GetSock(key, hashCode);
if (sock != null)
{
StringBuilder builder = new StringBuilder("delete ").Append(key);
if (expiry != DateTime.MaxValue)
{
builder.Append(" " + (GetExpirationTime(expiry) / 0x3e8));
}
builder.Append("\r\n");
try
{
sock.Write(Encoding.UTF8.GetBytes(builder.ToString()));
sock.Flush();
string newValue = sock.ReadLine();
if ("DELETED" == newValue)
{
bool isInfoEnabled = log.IsInfoEnabled;
sock.Close();
sock = null;
return true;
}
if ("NOT_FOUND" == newValue)
{
if (!log.IsInfoEnabled)
{
}
}
else if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("delete key error").Replace("$$Key$$", key).Replace("$$Line$$", newValue));
}
}
catch (IOException exception)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("delete IOException"), exception);
}
try
{
sock.TrueClose();
}
catch (IOException exception2)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("failed to close some socket").Replace("$$Socket$$", sock.ToString()), exception2);
}
}
sock = null;
}
if (sock != null)
{
sock.Close();
}
}
return false;
}
public bool FlushAll()
{
return this.FlushAll(null);
}
public bool FlushAll(ArrayList servers)
{
SockIOPool instance = SockIOPool.GetInstance(this._poolName);
if (instance == null)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("unable to get socket pool"));
}
return false;
}
if (servers == null)
{
servers = instance.Servers;
}
if ((servers == null) || (servers.Count <= 0))
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("flushall no servers"));
}
return false;
}
bool flag = true;
for (int i = 0; i < servers.Count; i++)
{
SockIO connection = instance.GetConnection((string) servers[i]);
if (connection == null)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("unable to connect").Replace("$$Server$$", servers[i].ToString()));
}
flag = false;
}
else
{
string s = "flush_all\r\n";
try
{
connection.Write(Encoding.UTF8.GetBytes(s));
connection.Flush();
string str2 = connection.ReadLine();
flag = ("OK" == str2) ? flag : false;
}
catch (IOException exception)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("flushall IOException"), exception);
}
try
{
connection.TrueClose();
}
catch (IOException exception2)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("failed to close some socket").Replace("$$Socket$$", connection.ToString()), exception2);
}
}
flag = false;
connection = null;
}
if (connection != null)
{
connection.Close();
}
}
}
return flag;
}
public object Get(string key)
{
return this.Get(key, null, false);
}
public object Get(string key, int hashCode)
{
return this.Get(key, hashCode, false);
}
public object Get(string key, object hashCode, bool asString)
{
SockIO sock = SockIOPool.GetInstance(this._poolName).GetSock(key, hashCode);
if (sock != null)
{
try
{
string s = "get " + key + "\r\n";
bool isDebugEnabled = log.IsDebugEnabled;
sock.Write(Encoding.UTF8.GetBytes(s));
sock.Flush();
Hashtable hm = new Hashtable();
this.LoadItems(sock, hm, asString);
bool flag2 = log.IsDebugEnabled;
sock.Close();
return hm[key];
}
catch (IOException exception)
{
//##监测##
//exception.Message=无法将数据写入传输连接: 远程主机强迫关闭了一个现有的连接。。
//原因:memcached重启类造成的连接池无法再通信的错误
//解决:判断上面的message出现次数几次,就考虑重新建立连接池
if (exception.Message.Contains("无法将数据写入传输连接: 远程主机强迫关闭了一个现有的连接"))
{
MemcachedSocksMonitor.SockIOErrRestatr();
}
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("get IOException").Replace("$$Key$$", key), exception);
}
try
{
sock.TrueClose();
}
catch (IOException exception2)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("failed to close some socket").Replace("$$Socket$$", sock.ToString()), exception2);
}
}
sock = null;
}
if (sock != null)
{
sock.Close();
}
}
return null;
}
public long GetCounter(string key)
{
return this.GetCounter(key, null);
}
public long GetCounter(string key, object hashCode)
{
if (key == null)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("getcounter null key"));
}
return -1L;
}
long num = -1L;
try
{
num = long.Parse((string) this.Get(key, hashCode, true), new NumberFormatInfo());
}
catch (ArgumentException)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("getcounter counter not found").Replace("$$Key$$", key));
}
}
return num;
}
private static int GetExpirationTime(DateTime expiration)
{
if (expiration <= DateTime.Now)
{
return 0;
}
TimeSpan span = new TimeSpan(0x1d, 0x17, 0x3b, 0x3b);
if (expiration.Subtract(DateTime.Now) > span)
{
return (int) span.TotalSeconds;
}
return (int) expiration.Subtract(DateTime.Now).TotalSeconds;
}
private static string GetLocalizedString(string key)
{
if (key != "default instance")
{
return key;
}
else
{
return _resourceManager.GetString(key);
}
}
public Hashtable GetMultiple(string[] keys)
{
return this.GetMultiple(keys, null, false);
}
public Hashtable GetMultiple(string[] keys, int[] hashCodes)
{
return this.GetMultiple(keys, hashCodes, false);
}
public Hashtable GetMultiple(string[] keys, int[] hashCodes, bool asString)
{
if (keys == null)
{
return new Hashtable();
}
Hashtable hashtable = new Hashtable();
for (int i = 0; i < keys.Length; i++)
{
object hashCode = null;
if ((hashCodes != null) && (hashCodes.Length > i))
{
hashCode = hashCodes[i];
}
SockIO sock = SockIOPool.GetInstance(this._poolName).GetSock(keys[i], hashCode);
if (sock != null)
{
if (!hashtable.ContainsKey(sock.Host))
{
hashtable[sock.Host] = new StringBuilder();
}
((StringBuilder) hashtable[sock.Host]).Append(" " + keys[i]);
sock.Close();
}
}
bool isInfoEnabled = log.IsInfoEnabled;
Hashtable hm = new Hashtable();
ArrayList list = new ArrayList();
foreach (string str in hashtable.Keys)
{
SockIO connection = SockIOPool.GetInstance(this._poolName).GetConnection(str);
try
{
string s = "get" + ((StringBuilder) hashtable[str]) + "\r\n";
bool flag2 = log.IsDebugEnabled;
connection.Write(Encoding.UTF8.GetBytes(s));
connection.Flush();
this.LoadItems(connection, hm, asString);
}
catch (IOException exception)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("getmultiple IOException"), exception);
}
list.Add(str);
try
{
connection.TrueClose();
}
catch (IOException exception2)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("failed to close some socket").Replace("$$Socket$$", connection.ToString()), exception2);
}
}
connection = null;
}
if (connection != null)
{
connection.Close();
}
}
foreach (string str3 in list)
{
hashtable.Remove(str3);
}
bool isDebugEnabled = log.IsDebugEnabled;
return hm;
}
public object[] GetMultipleArray(string[] keys)
{
return this.GetMultipleArray(keys, null, false);
}
public object[] GetMultipleArray(string[] keys, int[] hashCodes)
{
return this.GetMultipleArray(keys, hashCodes, false);
}
public object[] GetMultipleArray(string[] keys, int[] hashCodes, bool asString)
{
if (keys == null)
{
return new object[0];
}
Hashtable hashtable = this.GetMultiple(keys, hashCodes, asString);
object[] objArray = new object[keys.Length];
for (int i = 0; i < keys.Length; i++)
{
objArray[i] = hashtable[keys[i]];
}
return objArray;
}
public long Increment(string key)
{
return this.IncrementOrDecrement("incr", key, 1L, null);
}
public long Increment(string key, long inc)
{
return this.IncrementOrDecrement("incr", key, inc, null);
}
public long Increment(string key, long inc, int hashCode)
{
return this.IncrementOrDecrement("incr", key, inc, hashCode);
}
private long IncrementOrDecrement(string cmdname, string key, long inc, object hashCode)
{
SockIO sock = SockIOPool.GetInstance(this._poolName).GetSock(key, hashCode);
if (sock != null)
{
try
{
string s = string.Concat(new object[] { cmdname, " ", key, " ", inc, "\r\n" });
bool isDebugEnabled = log.IsDebugEnabled;
sock.Write(Encoding.UTF8.GetBytes(s));
sock.Flush();
string input = sock.ReadLine();
if (new Regex(@"\d+").Match(input).Success)
{
sock.Close();
return long.Parse(input, new NumberFormatInfo());
}
if ("NOT_FOUND" == input)
{
if (!log.IsInfoEnabled)
{
}
}
else if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("incr-decr key error").Replace("$$Key$$", key));
}
}
catch (IOException exception)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("incr-decr IOException"), exception);
}
try
{
sock.TrueClose();
}
catch (IOException)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("failed to close some socket").Replace("$$Socket$$", sock.ToString()));
}
}
sock = null;
}
if (sock != null)
{
sock.Close();
}
}
return -1L;
}
private void Init()
{
this._primitiveAsString = false;
this._compressEnable = true;
this._compressThreshold = 0x7800L;
this._defaultEncoding = "UTF-8";
this._poolName = GetLocalizedString("default instance");
}
public bool KeyExists(string key)
{
return (this.Get(key, null, true) != null);
}
private void LoadItems(SockIO sock, Hashtable hm, bool asString)
{
string str;
object obj2;
Label_0000:
str = sock.ReadLine();
bool isDebugEnabled = log.IsDebugEnabled;
if (!str.StartsWith("VALUE"))
{
if ("END" == str)
{
if (log.IsDebugEnabled)
{
}
return;
}
goto Label_0000;
}
string[] strArray = str.Split(new char[] { ' ' });
string newValue = strArray[1];
int num = int.Parse(strArray[2], new NumberFormatInfo());
int num2 = int.Parse(strArray[3], new NumberFormatInfo());
bool flag2 = log.IsDebugEnabled;
byte[] bytes = new byte[num2];
sock.Read(bytes);
sock.ClearEndOfLine();
if ((num & 2) != 0)
{
try
{
int num3;
GZipInputStream stream = new GZipInputStream(new MemoryStream(bytes));
MemoryStream stream2 = new MemoryStream(bytes.Length);
byte[] buffer = new byte[0x800];
while ((num3 = stream.Read(buffer, 0, buffer.Length)) > 0)
{
stream2.Write(buffer, 0, num3);
}
bytes = stream2.ToArray();
stream.Close();
}
catch (IOException exception)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("loaditems uncompression IOException").Replace("$$Key$$", newValue), exception);
}
throw new IOException(GetLocalizedString("loaditems uncompression IOException").Replace("$$Key$$", newValue), exception);
}
}
if ((num & 8) == 0)
{
if (this._primitiveAsString || asString)
{
bool isInfoEnabled = log.IsInfoEnabled;
obj2 = Encoding.GetEncoding(this._defaultEncoding).GetString(bytes);
goto Label_022A;
}
try
{
obj2 = NativeHandler.Decode(bytes);
goto Label_022A;
}
catch (Exception exception2)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("loaditems deserialize error").Replace("$$Key$$", newValue), exception2);
}
throw new IOException(GetLocalizedString("loaditems deserialize error").Replace("$$Key$$", newValue), exception2);
}
}
try
{
MemoryStream serializationStream = new MemoryStream(bytes);
obj2 = new BinaryFormatter().Deserialize(serializationStream);
bool flag4 = log.IsInfoEnabled;
}
catch (SerializationException exception3)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("loaditems SerializationException").Replace("$$Key$$", newValue), exception3);
}
throw new IOException(GetLocalizedString("loaditems SerializationException").Replace("$$Key$$", newValue), exception3);
}
Label_022A:
hm[newValue] = obj2;
goto Label_0000;
}
public bool Replace(string key, object value)
{
return this.Set("replace", key, value, DateTime.MaxValue, null, this._primitiveAsString);
}
public bool Replace(string key, object value, DateTime expiry)
{
return this.Set("replace", key, value, expiry, null, this._primitiveAsString);
}
public bool Replace(string key, object value, int hashCode)
{
return this.Set("replace", key, value, DateTime.MaxValue, hashCode, this._primitiveAsString);
}
public bool Replace(string key, object value, DateTime expiry, int hashCode)
{
return this.Set("replace", key, value, expiry, hashCode, this._primitiveAsString);
}
public bool Set(string key, object value)
{
return this.Set("set", key, value, DateTime.MaxValue, null, this._primitiveAsString);
}
public bool Set(string key, object value, DateTime expiry)
{
return this.Set("set", key, value, expiry, null, this._primitiveAsString);
}
public bool Set(string key, object value, int hashCode)
{
return this.Set("set", key, value, DateTime.MaxValue, hashCode, this._primitiveAsString);
}
public bool Set(string key, object value, DateTime expiry, int hashCode)
{
return this.Set("set", key, value, expiry, hashCode, this._primitiveAsString);
}
private bool Set(string cmdname, string key, object obj, DateTime expiry, object hashCode, bool asString)
{
byte[] bytes;
if (expiry < DateTime.Now)
{
return true;
}
if (((cmdname == null) || (cmdname.Trim().Length == 0)) || ((key == null) || (key.Length == 0)))
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("set key null"));
}
return false;
}
SockIO sock = SockIOPool.GetInstance(this._poolName).GetSock(key, hashCode);
if (sock == null)
{
return false;
}
if (expiry == DateTime.MaxValue)
{
expiry = new DateTime(0L);
}
int num = 0;
int count = 0;
if (NativeHandler.IsHandled(obj))
{
if (asString)
{
if (obj != null)
{
bool flag1 = log.IsInfoEnabled;
try
{
bytes = Encoding.UTF8.GetBytes(obj.ToString());
count = bytes.Length;
goto Label_01DF;
}
catch (ArgumentException exception)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("set invalid encoding").Replace("$$Encoding$$", this._defaultEncoding), exception);
}
sock.Close();
sock = null;
return false;
}
}
bytes = new byte[0];
count = 0;
goto Label_01DF;
}
bool isInfoEnabled = log.IsInfoEnabled;
try
{
bytes = NativeHandler.Encode(obj);
count = bytes.Length;
goto Label_01DF;
}
catch (ArgumentException exception2)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("set failed to native handle object"), exception2);
}
sock.Close();
sock = null;
return false;
}
}
if (obj != null)
{
bool flag3 = log.IsInfoEnabled;
try
{
MemoryStream serializationStream = new MemoryStream();
new BinaryFormatter().Serialize(serializationStream, obj);
bytes = serializationStream.GetBuffer();
count = (int) serializationStream.Length;
num |= 8;
goto Label_01DF;
}
catch (IOException exception3)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("set failed to serialize").Replace("$$Object$$", obj.ToString()), exception3);
}
sock.Close();
sock = null;
return false;
}
}
bytes = new byte[0];
count = 0;
Label_01DF:
if (this._compressEnable && (count > this._compressThreshold))
{
bool flag4 = log.IsInfoEnabled;
try
{
MemoryStream baseOutputStream = new MemoryStream();
GZipOutputStream stream3 = new GZipOutputStream(baseOutputStream);
stream3.Write(bytes, 0, count);
stream3.Finish();
bytes = baseOutputStream.GetBuffer();
count = (int) baseOutputStream.Length;
num |= 2;
bool flag5 = log.IsInfoEnabled;
}
catch (IOException exception4)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("set compression failure"), exception4);
}
}
}
try
{
string s = string.Concat(new object[] { cmdname, " ", key, " ", num, " ", GetExpirationTime(expiry), " ", count, "\r\n" });
sock.Write(Encoding.UTF8.GetBytes(s));
sock.Write(bytes, 0, count);
sock.Write(Encoding.UTF8.GetBytes("\r\n"));
sock.Flush();
string newValue = sock.ReadLine();
bool flag6 = log.IsInfoEnabled;
if ("STORED" == newValue)
{
bool flag7 = log.IsInfoEnabled;
sock.Close();
sock = null;
return true;
}
if ("NOT_STORED" == newValue)
{
if (!log.IsInfoEnabled)
{
}
}
else if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("set error").Replace("$$Key$$", key).Replace("$$Size$$", count.ToString(new NumberFormatInfo())).Replace("$$Line$$", newValue));
}
}
catch (IOException exception5)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("set IOException"), exception5);
}
//##监测##
//exception.Message=无法将数据写入传输连接: 远程主机强迫关闭了一个现有的连接。。
//原因:memcached重启类造成的连接池无法再通信的错误
//解决:判断上面的message出现次数几次,就考虑重新建立连接池
if (exception5.Message.Contains("无法将数据写入传输连接: 远程主机强迫关闭了一个现有的连接"))
{
MemcachedSocksMonitor.SockIOErrRestatr();
}
try
{
sock.TrueClose();
}
catch (IOException exception6)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("failed to close some socket").Replace("$$Socket$$", sock.ToString()), exception6);
}
}
sock = null;
}
if (sock != null)
{
sock.Close();
}
return false;
}
public Hashtable Stats()
{
return this.Stats(null);
}
public Hashtable Stats(ArrayList servers)
{
SockIOPool instance = SockIOPool.GetInstance(this._poolName);
if (instance == null)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("unable to get socket pool"));
}
return null;
}
if (servers == null)
{
servers = instance.Servers;
}
if ((servers == null) || (servers.Count <= 0))
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("stats no servers"));
}
return null;
}
Hashtable hashtable = new Hashtable();
for (int i = 0; i < servers.Count; i++)
{
SockIO connection = instance.GetConnection((string) servers[i]);
if (connection == null)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("unable to connect").Replace("$$Server$$", servers[i].ToString()));
}
continue;
}
string s = "stats\r\n";
try
{
connection.Write(Encoding.UTF8.GetBytes(s));
connection.Flush();
Hashtable hashtable2 = new Hashtable();
while (true)
{
string str2 = connection.ReadLine();
bool isDebugEnabled = log.IsDebugEnabled;
if (str2.StartsWith("STAT"))
{
string[] strArray = str2.Split(new char[] { ' ' });
string str3 = strArray[1];
string str4 = strArray[2];
bool flag2 = log.IsDebugEnabled;
hashtable2[str3] = str4;
}
else if ("END" == str2)
{
if (!log.IsDebugEnabled)
{
}
goto Label_01E4;
}
hashtable[servers[i]] = hashtable2;
}
}
catch (IOException exception)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("stats IOException"), exception);
}
try
{
connection.TrueClose();
}
catch (IOException)
{
if (log.IsErrorEnabled)
{
log.Error(GetLocalizedString("failed to close some socket").Replace("$$Socket$$", connection.ToString()));
}
}
connection = null;
}
Label_01E4:
if (connection != null)
{
connection.Close();
}
}
return hashtable;
}
public bool StoreCounter(string key, long counter)
{
return this.Set("set", key, counter, DateTime.MaxValue, null, true);
}
public bool StoreCounter(string key, long counter, int hashCode)
{
return this.Set("set", key, counter, DateTime.MaxValue, hashCode, true);
}
public long CompressionThreshold
{
get
{
return this._compressThreshold;
}
set
{
this._compressThreshold = value;
}
}
public string DefaultEncoding
{
get
{
return this._defaultEncoding;
}
set
{
this._defaultEncoding = value;
}
}
public bool EnableCompression
{
get
{
return this._compressEnable;
}
set
{
this._compressEnable = value;
}
}
public string PoolName
{
get
{
return this._poolName;
}
set
{
this._poolName = value;
}
}
public bool PrimitiveAsString
{
get
{
return this._primitiveAsString;
}
set
{
this._primitiveAsString = value;
}
}
}
}