ehcache3-源码简析二

ehcache对于offheap是如何管理的呢?从get操作可以一窥,这里以heap+offheap分层cache为例。

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 }

 

posted @ 2017-08-24 15:46  holoyong  阅读(1432)  评论(0编辑  收藏  举报