设为首页 收藏本站
查看: 539|回复: 0

[经验分享] tomcat文件缓存分析[一个bug]

[复制链接]

尚未签到

发表于 2017-1-31 07:54:34 | 显示全部楼层 |阅读模式
  =====================================
apache tomcat中文件的缓存机制
=====================================
一. 环境
 version: apache tomcat 5.5.26
 
二. 缓存机制[ServletContext.getResourceAsStream]
 1. 根据给出的path到缓存中查询CacheEntry; 以下是从ProxyDirContext类中摘出来的方法
  protected CacheEntry cacheLookup(String name) {
   if (cache == null)
    return (null);
   if (name == null)
    name = "";
   for (int i = 0; i < nonCacheable.length; i++) {
    if (name.startsWith(nonCacheable)) {
     return (null);
    }
   }
   CacheEntry cacheEntry = cache.lookup(name);
   if (cacheEntry == null) {
    cacheEntry = new CacheEntry();
    cacheEntry.name = name;
    // Load entry
    cacheLoad(cacheEntry);
    //注释:要特别注意cacheLoad这个方法, 它缓存文件最后修改时间时,并没有取真正的时间,仅仅缓存了
    //文件属性对象[这时候的修改时间为-1, 还没有, 只有等到下次对比的时候才取]
   } else {
    if (!validate(cacheEntry)) {
     if (!revalidate(cacheEntry)) {
      //注释: revalidate这个方法要注意,它是用文件的大小和最后修改时间来比较的
      
      cacheUnload(cacheEntry.name);
      return (null);
      //注释: 它清除缓存之后,并没有马上将新的内容加载到缓存中.
     } else {
      cacheEntry.timestamp =
       System.currentTimeMillis() + cacheTTL;
     }
    }
    cacheEntry.accessCount++;
   }
   return (cacheEntry);
  } 
  
  protected void cacheLoad(CacheEntry entry) {
  String name = entry.name;
  // Retrieve missing info
   boolean exists = true;
  //注释:出问题的点就在下面,它只将文件的属性对象缓存了,
   //并没有取文件的最后修改时间[它的初始化值是-1, 只有调用
   //之后,才会取得真正的最后修改时间].
   // Retrieving attributes
   if (entry.attributes == null) {
    try {
     Attributes attributes = dirContext.getAttributes(entry.name);
     if (!(attributes instanceof ResourceAttributes)) {
      entry.attributes =
       new ResourceAttributes(attributes);
     } else {
      entry.attributes = (ResourceAttributes) attributes;
     }
    } catch (NamingException e) {
     exists = false;
    }
   }
  ....
  }
  
 2. 如果找到CacheEntry, 则将CacheEntry.resource返回;
如果没有找到,则到文件系统加载指定的文件;
  从以上的分析来看,它的缓存有以下几个特点:
 > 从缓存中获取的时候,它是根据path获取一个CacheEntry对象,如果有,还需要验证这个对象是否有效,如果无效,就直接删除;
 > 删除缓存的内容时,并不马上将新的内容添加到缓存中,而只是简单的将缓存清空而已;
 > 建立缓存的时候,它将缓存对象[文件或资源]的属性也缓存了[但当时并没有取出最后修改时间]
 > 判断一个缓存对象是否有效的依据是:文件大小和文件的最后修改时间.
 
 由于tomcat在生成缓存对象的时候,只是将缓存对象的属性对象缓存起来,并没有获取"最后修改时间属性", 所以导致下一次对比缓存的
时候,缓存中的"最后修改时间属性"就是当前文件的最后修改时间.
 例如:
 [原始文件, 最后修改时间: 001]
 第一次访问: 缓存不存在, 生成缓存, 并生成缓存属性[缓存属性中的最后修改时间: -1]
 [第一次修改文件, 最后修改时间: 002]
 第二次访问: 缓存存在, 取得缓存对象, 对比时间和大小, 由于缓存属性的最后修改时间为-1, 所以取当前文件的最后修改时间
假设文件大小没有改变,所以就直接使用缓存中的内容[缓存属性中的最后修改时间: 002]
 [第二次修改文件, 最后修改时间: 003]
 第三次访问: 缓存存在,从缓存中取, 由于缓存中的最后修改时间与当前的最后修改时间不一样,所以清缓存;
 [第三次修改文件, 最后修改时间:004]
 第四次访问: 缓存不存在, 重复第一次访问的逻辑
 
 因此, 按以上逻辑, 第2, 5, 8, 11...(3*n-1, n为自然数)次访问的时候会出问题,没有取到最新的内容,而是上一次的缓存结果.
 这个问题的根据原因是:对时间属性的缓存,并没有缓存真正的时间(不知道tomcat出于什么原因,为什么缓存的时候不将最后修改时间
取出来?)
 
三. 说明
 1. CacheEntry上的关键属性:
  > resource或context: 表示缓存的内容
  > attributes: 表示缓存文件的一些属性;
  > name: 缓存文件的path;
 

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-335520-1-1.html 上篇帖子: dalvik on J2EE: running tomcat on dalvik 下篇帖子: How Tomcat Works 读书笔记(第五章)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表