修改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;
            }
        }
    }
}

 

 

Raw file: Serializer.cs

posted @ 2010-05-06 21:37  阿蒙  阅读(543)  评论(2)    收藏  举报