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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM