Grizzly 的 HTTP CoDec 实现方法更 Netty 的 CoDec 完全不同, 他们思想上的差异主要在于:

1. 解码方式

Grizzly 使用流式解码, 它的HttpHeader对象内部都是用的DataChunk这样的类来存储数据, 就是像是将一个类都分好格子, 里面有 InitialLine, HeaderName1, HederVal1, HeaderName2, HeaderVal2 这样, 这些格子都是用来放二进制数据的, 然后再读取到Buffer后将Buffer的数据往 类里面的格子里填进去. 只有在真正需要使用这些数据的时候才会将二进制数据转为字符串

Netty 的解码则是使用 ReplayingDecoder 的特性来实现, ReplayingDecoder 的特性是可以设置checkpoint, 如果说当前checkpoint还没有完成, 但是buffer的数据又读完了, 则会将当前的数据累计起来, 在下一次收到新buffer的时候从当前checkpoint重新decode, 如果checkpoint完成, 则转移到一下checkpoint, 并释放成功decode的数据. 他的好处在于当buffer被读完的时候(数据不够, 例如header才decode到一半buffer就读完了)则会抛出一个SIGNAL(SIGNAL是Netty自定义的ERROR), 捕捉到这个error以后则会自动累计数据. 这样我们就不需要自己去判断当前数据够不够, 而是当做当前数据已经足够来做decode(因为会自动累计)

在解码方式上, 实际上我更倾向于 Grizzly 的这种方式, 因为它不需要累计数据, 这样就减少了一次ByteBuf的分配, 更节省内存. 而从decode方法上看, 流式填数据decode的方法也更容易理解, 不像replaying decode这么绕难以理解

2. Cache

Grizzly 对 Decode 过程中出现的所有对象都做了Cache, 例如 HttpHeader, HttpContent 等对象, 这些对象的生存周期是整个Decode过程, 也就是在Decode开始的时候会获取这个Cache对象, 然后在Decode完成以后会清理Cache对象内部的数据, 再将它放回 Cache里, 另外, 这些Cache都是ThreadLocal的, 所以他们是肯定线程安全的. 而 Netty 中这些对象都是新生成的. 下面对Grizzly的Cache体系做一个介绍. 这些代码都在 ThreadCache类里.  先看图

最后在看看ThreadCache的代码

public final class ThreadCache {

    private static final ObjectCacheElement[] INITIAL_OBJECT_ARRAY = new ObjectCacheElement[16];

    /** 这个map用于通过className获取对应的CachedTypeIndex */
private static final Map<String, CachedTypeIndex> typeIndexMap =
new HashMap<String, CachedTypeIndex>(); /** 全局的index计数器, 用来初始化CachedTypeIndex */
private static int indexCounter; private static final ThreadLocal<ObjectCache> genericCacheAttr =
new ThreadLocal<ObjectCache>(); public static synchronized <E> CachedTypeIndex<E> obtainIndex(
Class<E> clazz, int size) {
return obtainIndex(clazz.getName(), clazz, size); } /**
* 获取CachedTypeIndex的方法, 也就是说每个类在获取这个CachedTypeIndex的时候,
* 他在ObjectCache的ObjectCacheElement的index就已经定下来了
* */
@SuppressWarnings("unchecked")
public static synchronized <E> CachedTypeIndex<E> obtainIndex(String name,
Class<E> clazz, int size) { CachedTypeIndex<E> typeIndex = typeIndexMap.get(name);
if (typeIndex == null) {
// 注意这里的indexCounter++, 每个类获取一次index就会+1
typeIndex = new CachedTypeIndex<E>(indexCounter++, name, clazz, size);
typeIndexMap.put(name, typeIndex);
} return typeIndex;
} public static <E> boolean putToCache(final CachedTypeIndex<E> index, final E o) {
return putToCache(Thread.currentThread(), index, o);
} public static <E> boolean putToCache(final Thread currentThread,
final CachedTypeIndex<E> index, final E o) {
if (currentThread instanceof DefaultWorkerThread) {
return ((DefaultWorkerThread) currentThread).putToCache(index, o);
} else {
ObjectCache genericCache = genericCacheAttr.get();
if (genericCache == null) {
genericCache = new ObjectCache();
genericCacheAttr.set(genericCache);
} return genericCache.put(index, o);
}
} /**
* Get the cached object with the given type index from cache.
* Unlike {@link #takeFromCache(org.glassfish.grizzly.ThreadCache.CachedTypeIndex)}, the
* object won't be removed from cache.
*
* @param <E>
* @param index the cached object type index.
* @return cached object.
*/
public static <E> E getFromCache(final CachedTypeIndex<E> index) {
return getFromCache(Thread.currentThread(), index);
} /**
* Get the cached object with the given type index from cache.
* Unlike {@link #takeFromCache(org.glassfish.grizzly.ThreadCache.CachedTypeIndex)}, the
* object won't be removed from cache.
*
* @param <E>
* @param currentThread current {@link Thread}
* @param index the cached object type index.
* @return cached object.
*/
public static <E> E getFromCache(final Thread currentThread,
final CachedTypeIndex<E> index) {
assert currentThread == Thread.currentThread(); if (currentThread instanceof DefaultWorkerThread) {
return ((DefaultWorkerThread) currentThread).getFromCache(index);
} else {
final ObjectCache genericCache = genericCacheAttr.get();
if (genericCache != null) {
return genericCache.get(index);
} return null;
}
} /**
* Take the cached object with the given type index from cache.
* Unlike {@link #getFromCache(org.glassfish.grizzly.ThreadCache.CachedTypeIndex)}, the
* object will be removed from cache.
*
* @param <E>
* @param index the cached object type index
* @return cached object
*/
public static <E> E takeFromCache(final CachedTypeIndex<E> index) {
return takeFromCache(Thread.currentThread(), index);
} /**
* Take the cached object with the given type index from cache.
* Unlike {@link #getFromCache(org.glassfish.grizzly.ThreadCache.CachedTypeIndex)}, the
* object will be removed from cache.
*
* @param <E>
* @param currentThread current {@link Thread}
* @param index the cached object type index
* @return cached object
*/
public static <E> E takeFromCache(final Thread currentThread,
final CachedTypeIndex<E> index) {
if (currentThread instanceof DefaultWorkerThread) {
return ((DefaultWorkerThread) currentThread).takeFromCache(index);
} else {
final ObjectCache genericCache = genericCacheAttr.get();
if (genericCache != null) {
return genericCache.take(index);
} return null;
}
} /** 实际存储cache的类 */
public static final class ObjectCache {
private ObjectCacheElement[] objectCacheElements; public boolean put(final CachedTypeIndex index, final Object o) {
if (objectCacheElements != null &&
index.getIndex() < objectCacheElements.length) {
ObjectCacheElement objectCache = objectCacheElements[index.getIndex()];
if (objectCache == null) {
objectCache = new ObjectCacheElement(index.size);
objectCacheElements[index.getIndex()] = objectCache;
} return objectCache.put(o);
} final ObjectCacheElement[] arrayToGrow =
(objectCacheElements != null) ?
objectCacheElements : INITIAL_OBJECT_ARRAY;
final int newSize = Math.max(index.getIndex() + 1,
(arrayToGrow.length * 3) / 2 + 1); objectCacheElements = Arrays.copyOf(arrayToGrow, newSize); final ObjectCacheElement objectCache = new ObjectCacheElement(index.getSize());
objectCacheElements[index.getIndex()] = objectCache;
return objectCache.put(o);
} /**
* Get the cached object with the given type index from cache.
* Unlike {@link #take(org.glassfish.grizzly.ThreadCache.CachedTypeIndex)}, the
* object won't be removed from cache.
*
* @param <E>
* @param index the cached object type index.
* @return cached object.
*/
@SuppressWarnings("unchecked")
public <E> E get(final CachedTypeIndex<E> index) {
final int idx;
if (objectCacheElements != null &&
(idx = index.getIndex()) < objectCacheElements.length) { final ObjectCacheElement objectCache = objectCacheElements[idx];
if (objectCache == null) return null; return (E) objectCache.get();
} return null;
} /**
* Take the cached object with the given type index from cache.
* Unlike {@link #get(org.glassfish.grizzly.ThreadCache.CachedTypeIndex)}, the
* object will be removed from cache.
*
* @param <E>
* @param index the cached object type index.
* @return cached object.
*/
@SuppressWarnings("unchecked")
public <E> E take(final CachedTypeIndex<E> index) {
final int idx;
if (objectCacheElements != null &&
(idx = index.getIndex()) < objectCacheElements.length) { final ObjectCacheElement objectCache = objectCacheElements[idx];
if (objectCache == null) return null; return (E) objectCache.take();
} return null;
}
} public static final class ObjectCacheElement {
private final int size;
private final Object[] cache;
private int index; public ObjectCacheElement(int size) {
this.size = size;
cache = new Object[size];
} public boolean put(Object o) {
if (index < size) {
cache[index++] = o;
return true;
} return false;
} /**
* Get (peek) the object from cache.
* Unlike {@link #take()} the object will not be removed from cache.
*
* @return object from cache.
*/
public Object get() {
if (index > 0) {
final Object o = cache[index - 1];
return o;
} return null;
} /**
* Take (poll) the object from cache.
* Unlike {@link #get()} the object will be removed from cache.
*
* @return object from cache.
*/
public Object take() {
if (index > 0) {
index--; final Object o = cache[index];
cache[index] = null;
return o;
} return null;
}
} public static final class CachedTypeIndex<E> {
private final int index;
private final Class clazz;
private final int size;
private final String name; public CachedTypeIndex(final int index, final String name,
final Class<E> clazz, final int size) {
this.index = index;
this.name = name;
this.clazz = clazz;
this.size = size;
} public int getIndex() {
return index;
} public String getName() {
return name;
} public Class getClazz() {
return clazz;
} public int getSize() {
return size;
}
}
}

最后来看看 CachedTypeIndex 都是在哪里生成的, 以 HttpClientFilter 中的 ClientHttpResponseImpl 为例

private static final class ClientHttpResponseImpl
extends HttpResponsePacket implements HttpPacketParsing { private static final ThreadCache.CachedTypeIndex<ClientHttpResponseImpl> CACHE_IDX =
ThreadCache.obtainIndex(ClientHttpResponseImpl.class, 16);

可见这些Cacheable的类在首次使用的时候就会把这个index给申请下来, 然后在ObjectCache的ObjectCacheElement[]里占上一个位子.之后它的index就已经是固定的了

Grizzly HTTP CoDec ThreadCache 浅析的更多相关文章

  1. netty5 HTTP协议栈浅析与实践

      一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...

  2. 浅析py-faster-rcnn中不同版本caffe的安装及其对应不同版本cudnn的解决方案

    浅析py-faster-rcnn中不同版本caffe的安装及其对应不同版本cudnn的解决方案 本文是截止目前为止最强攻略,按照本文方法基本可以无压力应对caffe和Ross B. Girshick的 ...

  3. Netty浅析

    Netty是JBoss出品的高效的Java NIO开发框架,关于其使用,可参考我的另一篇文章 netty使用初步.本文将主要分析Netty实现方面的东西,由于精力有限,本人并没有对其源码做了极细致的研 ...

  4. protobuf 协议浅析

    目录 Protobuf 协议浅析 1. Protobuf 介绍 1.1 Protobuf 基本概念 1.2 Protobuf 的优点 1.3 Protobuf, JSON, XML 的区别 2. Pr ...

  5. SQL Server on Linux 理由浅析

    SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...

  6. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  7. 高性能IO模型浅析

    高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking  ...

  8. Jvm 内存浅析 及 GC个人学习总结

    从诞生至今,20多年过去,Java至今仍是使用最为广泛的语言.这仰赖于Java提供的各种技术和特性,让开发人员能优雅的编写高效的程序.今天我们就来说说Java的一项基本但非常重要的技术内存管理 了解C ...

  9. 从源码浅析MVC的MvcRouteHandler、MvcHandler和MvcHttpHandler

    熟悉WebForm开发的朋友一定都知道,Page类必须实现一个接口,就是IHttpHandler.HttpHandler是一个HTTP请求的真正处理中心,在HttpHandler容器中,ASP.NET ...

随机推荐

  1. 远程执行shell

    目前我的需求是在我的hadoop集群搭建起来前,能定时做一下简易指标的监控,目前我的方案就是在我的server机上,定时执行远程脚本出指标数据,然后通过python脚本发送邮件. 远程执行脚本如下: ...

  2. js上传插件uploadify自动检测不到flash控件的问题

    [问题描述] 项目开发中,由于使用了js的一个上传插件uploadify,下载的是flash版本的,后来在谷歌浏览器上运行时经常报flash控件未安装,虽然下图是uploadify自动检测自动弹出来的 ...

  3. 关于我学XSS躺过的那些坑

    XSS字符编码 在学习编码绕过时由于数量多,类型相似,不太容易记得住,记得全,故做此记录. 0x01 Html标签属性中执行 简单了解: Html标签属性中的XSS问题多属于javascript伪协议 ...

  4. JAVA 画图板实现(基本画图功能+界面UI)一、界面实现

    /*文章中用到的代码只是一部分,需要源码的可通过邮箱联系我 1978702969@qq.com*/ 这段时间在学JAVA的swing界面开发,试着做了个画图板.实现了直线.曲线.喷枪.矩形.圆形.文字 ...

  5. codevs 水过 骑马修栅栏

    [问题描述] 农民John每年有很多栅栏要修理.他总是骑着马穿过每一个栅栏并修复它破损的地方. John是一个与其他农民一样懒的人.他讨厌骑马,因此从来不两次经过一个一个栅栏.你必须编一个程序,读入栅 ...

  6. Node.js开源应用OSN发布初始V1.0版本-见面版本

    Nodejs开源应用OSN初始版本V1.0发布,请参考本操作说明文档,有任何问题请留言 Nodejs开源应用OSN发布V1.0版本: OSChina收录地址: OSC收录地址:http://www.o ...

  7. BZOJ4175 : 小G的电话本

    用后缀树统计出出现了x次的本质不同的子串的个数,最后再乘以x,得到一个多项式. 这个多项式常数项为0,但是一次项不为0. 于是把整个多项式除以一次项,通过多项式求ln和多项式求exp求出它的幂. 最后 ...

  8. BZOJ 3400: [Usaco2009 Mar]Cow Frisbee Team 奶牛沙盘队 动态规划

    3400: [Usaco2009 Mar]Cow Frisbee Team 奶牛沙盘队 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=34 ...

  9. ORA-01591 锁定已被有问题的分配事务处理--解决方法(转)

    转载自love wife & love life —Roger 的Oracle技术博客 本文链接地址: ORA-01591: lock held by in-doubt distributed ...

  10. android 的几个黄色警告解决办法(转)

    转自:http://my.eoe.cn/864234/archive/5162.html 1:Handler 1 2 3 4 5 6 7 8 // This Handler class should ...