ehcache3-源码简析二

cache由heap+offheap组成时,authoritativeTier为OffHeapStore,OffHeapStore也会从map中get元素,该map就是EhcacheConcurrentOffHeapClockCache。EhcacheConcurrentOffHeapClockCache继承了AbstractConcurrentOffHeapMap,EhcacheConcurrentOffHeapClockCache也就具有了map的一些特性。AbstractConcurrentOffHeapMap中持有Segment数组,这点类似于jdk7中的ConcurrentHashMap,每一个Segment又是一个Map(但该Map有些特殊)。

 1 public abstract class AbstractConcurrentOffHeapMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>, ConcurrentMapInternals, HashingMap<K, V> {
 2
 3     protected final Segment<K, V>[] segments;
 4     //可设置的最大segment数
 5     private static final int MAX_SEGMENTS = 65536;
 6     //与jdk7中的ConcurrentHashMap一样,也有并发度的概念,即多少个segment
 7     private static final int DEFAULT_CONCURRENCY = 16;
 8
 9     //get元素时会调用该方法
10     public MetadataTuple<V> computeIfPresentWithMetadata(K key, BiFunction<? super K, ? super MetadataTuple<V>, ? extends MetadataTuple<V>> remappingFunction) {
11         //segmentFor会根据key的hash值找到对应的segment,在具体的segment上执行get操作(computeIfPresentWithMetadata),类似jdk7中的ConcurrentHashMap的逻辑
12         return this.segmentFor(key).computeIfPresentWithMetadata(key, remappingFunction);
13     }
14 }

EhcacheSegment继承了OffHeapHashMap,即EhcacheSegment也具有map的特征,但这个map不一般。

 1 public class OffHeapHashMap<K, V> extends AbstractMap<K, V> implements MapInternals, Owner, HashingMap<K, V> {
 2
 3     //......
 4
 5     //EhcacheSegment中的hashtable为一个IntBuffer,这就是它的特别之处,这个IntBuffer是一块offheap内存(DirectByteBuffer)
 6     protected volatile IntBuffer hashtable;
 7     //hashtable的初始大小,128个entry
 8     private static final int INITIAL_TABLE_SIZE = 128;
 9     //resize大小,即负载因子
10     private static final float TABLE_RESIZE_THRESHOLD = 0.5F;
11     //entry大小,4个int
12     protected static final int ENTRY_SIZE = 4;
13     //entry第0个int
14     protected static final int STATUS = 0;
15     //entry第1个int,代表hashcode
16     protected static final int KEY_HASHCODE = 1;
17     //entry第2、3个int,代表key的offheap地址
18     protected static final int ENCODING = 2;
19
20     //......
21
22     //EhcacheSegment的get操作
23     public MetadataTuple<V> computeIfPresentWithMetadata(K key, BiFunction<? super K, ? super MetadataTuple<V>, ? extends MetadataTuple<V>> remappingFunction) {
24       this.freePendingTables();
25       int hash = key.hashCode();
26       //hashtable是一个IntBuffer,该intBuffer中没4个int构成一个元素(entry),
27       //entry中第一个int表示existingStatus,第二个int表示hash,后两个int组成的long表示key在offheap中的位置。
28       //hashtable使用线性探测解决hash冲突,这里indexFor得到key在hashtable中未冲突的索引。
29       int start = this.indexFor(spread(hash));
30       //设置hashtable(intBuffer)的position,意在读取hashtable时,从start开始读,也即从key首次映射的索引开始读。
31       this.hashtable.position(start);
32       int limit = this.reprobeLimit();
33
34         //开始线性探测
35       for(int i = 0; i < limit; ++i) {
36         if (!this.hashtable.hasRemaining()) {
37           this.hashtable.rewind();
38         }
39
40         IntBuffer entry = (IntBuffer)this.hashtable.slice().limit(4);
41         if (isTerminating(entry)) {
42           return null;
43         }
44             //readLong(entry,2)就是从entry中读取一个地址(storageEngine可以根据该地址读取key、value),根据该地址再从storageEngine中获取key的真实值;
45             //entry.get(1)是读取hash值。
46         if (isPresent(entry) && this.keyEquals(key, hash, readLong((IntBuffer)entry, 2), entry.get(1))) {
47           long existingEncoding = readLong((IntBuffer)entry, 2);
48           int existingStatus = entry.get(0);
49           //storageEngine.readValue会根据existingEncoding(即address)获取value,此时得到的existingValue是一个DirectByteBuffer
50           MetadataTuple<V> existingValue = MetadataTuple.metadataTuple(this.storageEngine.readValue(existingEncoding), existingStatus & -4);
51           //对DirectByteBuffer进行detach
52           MetadataTuple<V> result = (MetadataTuple)remappingFunction.apply(key, existingValue);
53           //.....
54           return result;
55         }
56             //线性探测的下一个
57         this.hashtable.position(this.hashtable.position() + 4);
58       }
59
60       return null;
61     }
62
63     //有相应的expand、shrink方法对hashtable进行动态调整
64     //......
65
66 }
 1 //detach
 2 void detach() {
 3     if (mode == Mode.ATTACHED) {
 4       byte[] bytes = new byte[binaryValue.remaining()];
 5       binaryValue.get(bytes);
 6       binaryValue = ByteBuffer.wrap(bytes);
 7       mode = Mode.DETACHED;
 8     } else {
 9       throw new IllegalStateException("OffHeapValueHolder in mode " + mode + " cannot be prepared for delayed deserialization");
10     }
11 }
1 //OffHeapBufferStorageEngine根据address读取value
2 public ByteBuffer readValueBuffer(long address) {
3   int keyLength = this.storageArea.readInt(address + 4L);
4   int valueLength = this.storageArea.readInt(address + 8L);
5    //address, length
6   return this.storageArea.readBuffer(address + 12L + (long)keyLength, valueLength).asReadOnlyBuffer();
7 }
时间: 2024-08-02 16:40:51

ehcache3-源码简析二的相关文章

Linux Hugetlbfs内核源码简析-----(二)Hugetlbfs挂载

本文只讨论执行"mount none /mnt/huge -t hugetlbfs"命令后,mount系统调用的执行过程(基于Linux-3.4.51),不涉及进程相关的细节. mount系统调用的内核实现: 1 SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, 2 char __user *, type, unsigned long, flags, void __user *, data)

SpringMVC学习——概念、流程图、源码简析(一)

学习资料:开涛的<跟我学SpringMVC.pdf> 众所周知,springMVC是比较常用的web框架,通常整合spring使用.这里抛开spring,单纯的对springMVC做一下总结. 概念 HandlerMapping:处理器映射,对请求的URL进行映射为具体的处理器(如果有拦截器也包含拦截器,会将Handler和多个HandlerInterceptor封装为HandlerExecutionChain对象) HandlerAdapter:处理器适配器,适配不同类型的处理器,如Cont

并发工具-CyclicBarrier源码简析

CyclicBarrier是循环栅栏的意思,循环的等待多个线程执行任务: <1> 示例代码如下: public class CyclicBarrierTest { public static CyclicBarrier cb = new CyclicBarrier(3, () -> System.out.println("-------开始点名-------")); public static void main(String[] args) { System.out

0002 - Spring MVC 拦截器源码简析:拦截器加载与执行

1.概述 Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理.例如通过拦截器可以进行权限验证.记录请求信息的日志.判断用户是否登录等. 2.简单示例 2.1.继承 HandlerInterceptorAdapter 抽象类实现一个拦截器.代码如下: public class DemoInterceptor extends HandlerInterceptorAdapter { @Override    pu

JDK源码简析--java.lang包中的基础类库

题记 JDK,Java Development Kit. 我们必须先认识到,JDK只是,仅仅是一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含量来说,还是在一个层级上,它们都是需要被编译成字节码,在JRE中运行的,JDK编译后的结果就是jre/lib下得rt.jar,我们学习使用它的目的是加深对Java的理解,提高我们的Java编码水平. 本系列所有文章基于的JDK版本都是1.7.16. 本节内容 在本节中,简析java.lang包所包

JDK源码简析--java.util包中的工具类库

题记 JDK,Java Development Kit. 我们必须先认识到,JDK只是,仅仅是一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含量来说,还是在一个层级上,它们都是需要被编译成字节码,在JRE中运行的,JDK编译后的结果就是jre/lib下得rt.jar,我们学习使用它的目的是加深对Java的理解,提高我们的Java编码水平. 本系列所有文章基于的JDK版本都是1.7.16. 本节内容 在本节中,简析java.util包所包

Linux Hugetlbfs内核源码简析-----(一)Hugetlbfs初始化

一.引言 为了实现虚拟内存管理机制,操作系统对内存实行分页管理.自内存“分页机制”提出之始,内存页面的默认大小便被设置为 4096 字节(4KB),虽然原则上内存页面大小是可配置的,但绝大多数的操作系统实现中仍然采用默认的 4KB 页面.当某些应用的需要使用的内存达到几G.甚至几十G的时候,4KB的内存页面将严重制约程序的性能. CPU缓存中有一组缓存专门用于缓存TLB,但其大小是有限的.当采用的默认页面大小为 4KB,其产生的TLB较大,因而将会产生较多 TLB Miss 和缺页中断,从而大大

[tomcat]源码简析 异步/非阻塞和请求构成

提出疑惑 SpringFramework5.0又新增加了一个功能Webflux(响应式编程),是一个典型非阻塞异步的框架.我们知道servlet3.0实现异步(AsyncContext),servlet3.1又提出了非阻塞IO.对此我一直有两点疑惑:1.tomcat8底层已经默认使用NIO了,不是已经是IO非阻塞了吗,怎么又说servlet3.1解决了非阻塞.2.关于异步,如果开发者在serlvet中开一个业务线程来实现,也算异步,为什么3.0还提供了一个组件来解决,那么这种方式和开发者自己开个

第五节:JQuery框架源码简析(1)

(转自老惠的博客) JQuery是一个应用广泛.非常优秀的JavaScript框架,其代码简洁而优雅,有很多值得我们学习的地方.这里仅仅对其代码结构做一个简单的分析,方便大家的理解和学习. 我们进行分析.分解的基准版本是jQuery1.7.1. 开始之前,请准备好以下素材和工具: jQuery源代码:jquery-1.7.1.js 文本编辑器:EditPlus,或者你喜欢的 参考书:<jQuery高级编程>.<jQuery技术内幕:深入解析jQuery架构设计与实现原理>.<

Android -- Camera源码简析,启动流程

com.android.camera.Camera.java,主要的实现Activity,继承于ActivityBase. ActivityBase 在ActivityBase中执行流程: onCreate中进行判断是否是平板: onResume中判断是否锁屏,锁屏&camera不存在时候,mOnResumePending置为true,否则置为false并执行doOnResume: onWindowFocusChanged中判断是否获取到焦点&mOnResumePending,满足的话执行