修改memecache客户端API,解决ttserver反序列化问题
之前在一篇随笔中提到使用Memcache的API无法正确将保存在ttserver中的值正确反序列化,原因是,Memcache协议中的对象类型值未被保存到ttserver上,于是简单的修改了一下Memcache API(使用的beit-memcached)中的Serializer.cs文件,将序列化对象的原始类型保存在序列化串的第一个字节中,也就是将值的类型,连同值一起保存到ttserver上。

//Copyright (c) 2007-2008 Henrik Schr鰀er, Oliver Kofoed Pedersen
//Permission is hereby granted, free of charge, to any person
//obtaining a copy of this software and associated documentation
//files (the "Software"), to deal in the Software without
//restriction, including without limitation the rights to use,
//copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the
//Software is furnished to do so, subject to the following
//conditions:
//The above copyright notice and this permission notice shall be
//included in all copies or substantial portions of the Software.
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//OTHER DEALINGS IN THE SOFTWARE.
#region 文件信息
/*=================================================================
* 文件:Serializer.cs
* 创建者:<原作者>
* 创建日期:<未知>
* 最后修改:(楼下请注意保持队形)
* ##############################################################
* 时间 修改人 备注
* 2010-04-19 田真 因为TT不支持Memcached的类型存储,这里修改了序列化方式,主要体现在对Serialize和Deserialize方法的修改
* 2010-04-19 田真 增加了MergedBuffer和ParsedBuffer两个方法
* 2010-04-19 田真 修改SerializedType继承自byte,以前是ushort
* 2010-04-19 田真 修改CompressedByteArray = 255, CompressedObject = 256, CompressedString = 257
* 为:CompressedByteArray = 253, CompressedObject = 254, CompressedString = 255
* ##############################################################
* ================================================================*/
#endregion
using System;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
namespace SubCon.Caching.MemCached
{
/// <summary>
/// 序列化的对象类型
/// </summary>
internal enum SerializedType : byte
{
ByteArray = 0,
Object = 1,
String = 2,
Datetime = 3,
Bool = 4,
//SByte = 5, //Makes no sense.
Byte = 6,
Short = 7,
UShort = 8,
Int = 9,
UInt = 10,
Long = 11,
ULong = 12,
Float = 13,
Double = 14,
CompressedByteArray = 253,
CompressedObject = 254,
CompressedString = 255,
}
/// <summary>
/// 存储值序列器
/// </summary>
internal class Serializer
{
/// <summary>
/// 序列化存储值
/// </summary>
/// <param name="value">要进行序列化的值</param>
/// <param name="type">被序列的值是什么类型</param>
/// <param name="compressionThreshold">压缩基准,当序列化后的字节数组长度大于该值时进行压缩</param>
/// <returns></returns>
public static byte[] Serialize(object value, out SerializedType type, uint compressionThreshold) {
byte[] bytes;
if (value is byte[]) {
bytes = (byte[])value;
type = SerializedType.ByteArray;
if (bytes.Length > compressionThreshold) {
bytes = Compress(bytes);
type = SerializedType.CompressedByteArray;
}
} else if (value is string) {
bytes = Encoding.UTF8.GetBytes((string)value);
type = SerializedType.String;
if (bytes.Length > compressionThreshold) {
bytes = Compress(bytes);
type = SerializedType.CompressedString;
}
} else if (value is DateTime) {
bytes = BitConverter.GetBytes(((DateTime)value).Ticks);
type = SerializedType.Datetime;
} else if (value is bool) {
bytes = new byte[]{(byte)((bool)value ? 1 : 0)};
type = SerializedType.Bool;
} else if (value is byte) {
bytes = new byte[]{(byte)value};
type = SerializedType.Byte;
} else if (value is short) {
bytes = BitConverter.GetBytes((short)value);
type = SerializedType.Short;
} else if (value is ushort) {
bytes = BitConverter.GetBytes((ushort)value);
type = SerializedType.UShort;
} else if (value is int) {
bytes = BitConverter.GetBytes((int)value);
type = SerializedType.Int;
} else if (value is uint) {
bytes = BitConverter.GetBytes((uint)value);
type = SerializedType.UInt;
} else if (value is long) {
bytes = BitConverter.GetBytes((long)value);
type = SerializedType.Long;
} else if (value is ulong) {
bytes = BitConverter.GetBytes((ulong)value);
type = SerializedType.ULong;
} else if (value is float) {
bytes = BitConverter.GetBytes((float)value);
type = SerializedType.Float;
} else if (value is double) {
bytes = BitConverter.GetBytes((double)value);
type = SerializedType.Double;
} else {
//Object
using(MemoryStream ms = new MemoryStream()) {
new BinaryFormatter().Serialize(ms, value);
bytes = ms.ToArray();
type = SerializedType.Object;
if (bytes.Length > compressionThreshold) {
bytes = Compress(bytes);
type = SerializedType.CompressedObject;
}
}
}
//针对TT进行的修改
//edited by: 2010-4-19
//田真
return MergedBuffer(bytes, type);
}
/// <summary>
/// 解析缓存字节数组,解析出实际数据和数据类型
/// </summary>
/// <param name="buffer"></param>
/// <param name="type"></param>
/// <returns></returns>
private static byte[] ParsedBuffer(byte[] buffer, out SerializedType type)
{
//构造实际数据字节数组
byte[] bytes = new byte[buffer.Length - 1];
//提取类型
if (!Enum.IsDefined(typeof(SerializedType), buffer[0]))
type = SerializedType.ByteArray;
else
type = (SerializedType)buffer[0];
//提取数据
Buffer.BlockCopy(buffer, 1, bytes, 0, bytes.Length);
return bytes;
}
/// <summary>
/// 将序列化类型整合到存储的字节数组中(因为TT不支持Memcached的Type值存储)
/// </summary>
/// <param name="bytes">字节数组</param>
/// <param name="type">字节数组的类型</param>
/// <returns></returns>
private static byte[] MergedBuffer(byte[] bytes, SerializedType type)
{
//增加一个字节,用于存放字节数组的类型
byte[] buffer = new byte[bytes.Length + 1];
//将类型存储到第一个字节中
buffer[0] = (byte)type;
Buffer.BlockCopy(bytes, 0, buffer, 1, bytes.Length);
return buffer;
}
/// <summary>
/// 压缩指定的字节数组
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
private static byte[] Compress(byte[] bytes) {
using (MemoryStream ms = new MemoryStream()) {
using (DeflateStream gzs = new DeflateStream(ms, CompressionMode.Compress, false)) {
gzs.Write(bytes, 0, bytes.Length);
}
ms.Close();
return ms.ToArray();
}
}
/// <summary>
/// 解压缩指定的字节数组
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
private static byte[] Decompress (byte[] bytes) {
using (MemoryStream ms = new MemoryStream(bytes, false)) {
using(DeflateStream gzs = new DeflateStream(ms, CompressionMode.Decompress, false)) {
using(MemoryStream dest = new MemoryStream()) {
byte[] tmp = new byte[bytes.Length];
int read;
while ((read = gzs.Read(tmp, 0, tmp.Length)) != 0) {
dest.Write(tmp, 0, read);
}
dest.Close();
return dest.ToArray();
}
}
}
}
/// <summary>
/// 反序列化数据
/// </summary>
/// <param name="bytes"></param>
/// <param name="type"></param>
/// <returns></returns>
public static object Deserialize(byte[] bytes, SerializedType type) {
//针对TT进行的修改
//edited by: 2010-4-19
//田真
bytes = ParsedBuffer(bytes, out type);
switch (type) {
case SerializedType.String:
return Encoding.UTF8.GetString(bytes);
case SerializedType.Datetime:
return new DateTime(BitConverter.ToInt64(bytes, 0));
case SerializedType.Bool:
return bytes[0] == 1;
case SerializedType.Byte:
return bytes[0];
case SerializedType.Short:
return BitConverter.ToInt16(bytes, 0);
case SerializedType.UShort:
return BitConverter.ToUInt16(bytes, 0);
case SerializedType.Int:
return BitConverter.ToInt32(bytes, 0);
case SerializedType.UInt:
return BitConverter.ToUInt32(bytes, 0);
case SerializedType.Long:
return BitConverter.ToInt64(bytes, 0);
case SerializedType.ULong:
return BitConverter.ToUInt64(bytes, 0);
case SerializedType.Float:
return BitConverter.ToSingle(bytes, 0);
case SerializedType.Double:
return BitConverter.ToDouble(bytes, 0);
case SerializedType.Object:
using(MemoryStream ms = new MemoryStream(bytes)) {
return new BinaryFormatter().Deserialize(ms);
}
case SerializedType.CompressedByteArray:
return Deserialize(Decompress(bytes), SerializedType.ByteArray);
case SerializedType.CompressedString:
return Deserialize(Decompress(bytes), SerializedType.String);
case SerializedType.CompressedObject:
return Deserialize(Decompress(bytes), SerializedType.Object);
case SerializedType.ByteArray:
default:
return bytes;
}
}
}
}
//Permission is hereby granted, free of charge, to any person
//obtaining a copy of this software and associated documentation
//files (the "Software"), to deal in the Software without
//restriction, including without limitation the rights to use,
//copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the
//Software is furnished to do so, subject to the following
//conditions:
//The above copyright notice and this permission notice shall be
//included in all copies or substantial portions of the Software.
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//OTHER DEALINGS IN THE SOFTWARE.
#region 文件信息
/*=================================================================
* 文件:Serializer.cs
* 创建者:<原作者>
* 创建日期:<未知>
* 最后修改:(楼下请注意保持队形)
* ##############################################################
* 时间 修改人 备注
* 2010-04-19 田真 因为TT不支持Memcached的类型存储,这里修改了序列化方式,主要体现在对Serialize和Deserialize方法的修改
* 2010-04-19 田真 增加了MergedBuffer和ParsedBuffer两个方法
* 2010-04-19 田真 修改SerializedType继承自byte,以前是ushort
* 2010-04-19 田真 修改CompressedByteArray = 255, CompressedObject = 256, CompressedString = 257
* 为:CompressedByteArray = 253, CompressedObject = 254, CompressedString = 255
* ##############################################################
* ================================================================*/
#endregion
using System;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
namespace SubCon.Caching.MemCached
{
/// <summary>
/// 序列化的对象类型
/// </summary>
internal enum SerializedType : byte
{
ByteArray = 0,
Object = 1,
String = 2,
Datetime = 3,
Bool = 4,
//SByte = 5, //Makes no sense.
Byte = 6,
Short = 7,
UShort = 8,
Int = 9,
UInt = 10,
Long = 11,
ULong = 12,
Float = 13,
Double = 14,
CompressedByteArray = 253,
CompressedObject = 254,
CompressedString = 255,
}
/// <summary>
/// 存储值序列器
/// </summary>
internal class Serializer
{
/// <summary>
/// 序列化存储值
/// </summary>
/// <param name="value">要进行序列化的值</param>
/// <param name="type">被序列的值是什么类型</param>
/// <param name="compressionThreshold">压缩基准,当序列化后的字节数组长度大于该值时进行压缩</param>
/// <returns></returns>
public static byte[] Serialize(object value, out SerializedType type, uint compressionThreshold) {
byte[] bytes;
if (value is byte[]) {
bytes = (byte[])value;
type = SerializedType.ByteArray;
if (bytes.Length > compressionThreshold) {
bytes = Compress(bytes);
type = SerializedType.CompressedByteArray;
}
} else if (value is string) {
bytes = Encoding.UTF8.GetBytes((string)value);
type = SerializedType.String;
if (bytes.Length > compressionThreshold) {
bytes = Compress(bytes);
type = SerializedType.CompressedString;
}
} else if (value is DateTime) {
bytes = BitConverter.GetBytes(((DateTime)value).Ticks);
type = SerializedType.Datetime;
} else if (value is bool) {
bytes = new byte[]{(byte)((bool)value ? 1 : 0)};
type = SerializedType.Bool;
} else if (value is byte) {
bytes = new byte[]{(byte)value};
type = SerializedType.Byte;
} else if (value is short) {
bytes = BitConverter.GetBytes((short)value);
type = SerializedType.Short;
} else if (value is ushort) {
bytes = BitConverter.GetBytes((ushort)value);
type = SerializedType.UShort;
} else if (value is int) {
bytes = BitConverter.GetBytes((int)value);
type = SerializedType.Int;
} else if (value is uint) {
bytes = BitConverter.GetBytes((uint)value);
type = SerializedType.UInt;
} else if (value is long) {
bytes = BitConverter.GetBytes((long)value);
type = SerializedType.Long;
} else if (value is ulong) {
bytes = BitConverter.GetBytes((ulong)value);
type = SerializedType.ULong;
} else if (value is float) {
bytes = BitConverter.GetBytes((float)value);
type = SerializedType.Float;
} else if (value is double) {
bytes = BitConverter.GetBytes((double)value);
type = SerializedType.Double;
} else {
//Object
using(MemoryStream ms = new MemoryStream()) {
new BinaryFormatter().Serialize(ms, value);
bytes = ms.ToArray();
type = SerializedType.Object;
if (bytes.Length > compressionThreshold) {
bytes = Compress(bytes);
type = SerializedType.CompressedObject;
}
}
}
//针对TT进行的修改
//edited by: 2010-4-19
//田真
return MergedBuffer(bytes, type);
}
/// <summary>
/// 解析缓存字节数组,解析出实际数据和数据类型
/// </summary>
/// <param name="buffer"></param>
/// <param name="type"></param>
/// <returns></returns>
private static byte[] ParsedBuffer(byte[] buffer, out SerializedType type)
{
//构造实际数据字节数组
byte[] bytes = new byte[buffer.Length - 1];
//提取类型
if (!Enum.IsDefined(typeof(SerializedType), buffer[0]))
type = SerializedType.ByteArray;
else
type = (SerializedType)buffer[0];
//提取数据
Buffer.BlockCopy(buffer, 1, bytes, 0, bytes.Length);
return bytes;
}
/// <summary>
/// 将序列化类型整合到存储的字节数组中(因为TT不支持Memcached的Type值存储)
/// </summary>
/// <param name="bytes">字节数组</param>
/// <param name="type">字节数组的类型</param>
/// <returns></returns>
private static byte[] MergedBuffer(byte[] bytes, SerializedType type)
{
//增加一个字节,用于存放字节数组的类型
byte[] buffer = new byte[bytes.Length + 1];
//将类型存储到第一个字节中
buffer[0] = (byte)type;
Buffer.BlockCopy(bytes, 0, buffer, 1, bytes.Length);
return buffer;
}
/// <summary>
/// 压缩指定的字节数组
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
private static byte[] Compress(byte[] bytes) {
using (MemoryStream ms = new MemoryStream()) {
using (DeflateStream gzs = new DeflateStream(ms, CompressionMode.Compress, false)) {
gzs.Write(bytes, 0, bytes.Length);
}
ms.Close();
return ms.ToArray();
}
}
/// <summary>
/// 解压缩指定的字节数组
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
private static byte[] Decompress (byte[] bytes) {
using (MemoryStream ms = new MemoryStream(bytes, false)) {
using(DeflateStream gzs = new DeflateStream(ms, CompressionMode.Decompress, false)) {
using(MemoryStream dest = new MemoryStream()) {
byte[] tmp = new byte[bytes.Length];
int read;
while ((read = gzs.Read(tmp, 0, tmp.Length)) != 0) {
dest.Write(tmp, 0, read);
}
dest.Close();
return dest.ToArray();
}
}
}
}
/// <summary>
/// 反序列化数据
/// </summary>
/// <param name="bytes"></param>
/// <param name="type"></param>
/// <returns></returns>
public static object Deserialize(byte[] bytes, SerializedType type) {
//针对TT进行的修改
//edited by: 2010-4-19
//田真
bytes = ParsedBuffer(bytes, out type);
switch (type) {
case SerializedType.String:
return Encoding.UTF8.GetString(bytes);
case SerializedType.Datetime:
return new DateTime(BitConverter.ToInt64(bytes, 0));
case SerializedType.Bool:
return bytes[0] == 1;
case SerializedType.Byte:
return bytes[0];
case SerializedType.Short:
return BitConverter.ToInt16(bytes, 0);
case SerializedType.UShort:
return BitConverter.ToUInt16(bytes, 0);
case SerializedType.Int:
return BitConverter.ToInt32(bytes, 0);
case SerializedType.UInt:
return BitConverter.ToUInt32(bytes, 0);
case SerializedType.Long:
return BitConverter.ToInt64(bytes, 0);
case SerializedType.ULong:
return BitConverter.ToUInt64(bytes, 0);
case SerializedType.Float:
return BitConverter.ToSingle(bytes, 0);
case SerializedType.Double:
return BitConverter.ToDouble(bytes, 0);
case SerializedType.Object:
using(MemoryStream ms = new MemoryStream(bytes)) {
return new BinaryFormatter().Deserialize(ms);
}
case SerializedType.CompressedByteArray:
return Deserialize(Decompress(bytes), SerializedType.ByteArray);
case SerializedType.CompressedString:
return Deserialize(Decompress(bytes), SerializedType.String);
case SerializedType.CompressedObject:
return Deserialize(Decompress(bytes), SerializedType.Object);
case SerializedType.ByteArray:
default:
return bytes;
}
}
}
}
Raw file: Serializer.cs