
分頁緩存預加載算法:
將數據分頁(塊)存儲在緩存,這個頁(塊),一般大於應用實際請求的頁面大小,分頁(塊)緩存的加載采取預加載方式,即在應用分頁請求還沒讀到分頁(塊)的最后一頁數據時,即預先加載下一頁的緩存。這樣做有點如下:(1)減少DB讀取次數。(2)減少緩存傳輸數據大小。(3)預加載分頁緩存則避免應用請求超時。
令:
total : 記錄總數
cm :緩存大小,每一次緩存的記錄條數
cp :當前緩存頁數
n :一次請求多少條數
p :當前請求第幾頁
x :提前幾頁開始預加載緩存
bucket:緩存第幾頁(塊)
begin : 從緩存的第幾條開始取
threshold : 觸發讀取DB條件。
令:cm >= n+ n*x 保證緩存數據可供至少請求一次才觸發預加載
則:
bucket = (p * n) / cm + 1
begin = (p - 1) * n + 1
threshold :((p * n) % cm + n * x) >= cm
算法描述:
- 初始化加載緩存,從DB中取cm條記錄存入緩存。
- 應用分頁請求時,如果:
- (p * n) % cm >= n,在第(p * n) / cm + 1頁緩存從((p - 1) * n ) % cm + 1 條開始取n條記錄返回
- (p * n) % cm < n , 請求跨了兩個(頁)緩存,需要在兩個緩存中各取一部分數據拼接返回。在緩存從 (p * n) / cm 頁緩存中從 ((p - 1)*n - 1) % cm + 1條開始取 n - (p * n) % cm 條加上,在緩存從(p * n) / cm + 1頁緩存中從第1條開始取(p * n) % cm條合並返回。
- 如果 (p * n) % cm + n * x >= cm ,觸發預加載,即從DB中加載cm條記錄至緩存。
- 結束。
算法demo:
package com.xx.lt;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Jenkin.K on 17/6/1.
*/
public class PageCache {
Map<Integer,Cache> cacheMemory = new HashMap<Integer, Cache>();
Map<Integer, Record> dbData;
int cm = 50; //緩存大小
int bucket ; //當前緩存頁
int begin ; //從緩存的第幾條開始取
int n ; //一次請求多少條
int p ; //當前請求第幾頁
int x = 2; //提前
public static void main(String args[]){
PageCache pageCache = new PageCache();
pageCache.dbData = pageCache.initData();
pageCache.cacheMemory.put(1, pageCache.loadCache(pageCache.cm, 1));
int total = 1000;
int pageSize = 6;
for(int i = 0; i < total/pageSize - 1; i++) {
System.out.println("get "+ (i+1) +" page :" );
pageCache.getPage(i + 1, pageSize);
}
System.out.println(pageCache.cacheMemory);
}
private Map<Integer, Record> initData(){
Map<Integer, Record> data = new HashMap<Integer, Record>();
for(int i = 0; i < 1000; i++){
data.put(i+1, new Record(i+1));
}
return data;
}
public void getPage(int p, int n){
Map<Integer, Record> page = new HashMap<Integer, Record>();
bucket = (p * n) / cm + 1; //求當前取哪頁緩存
begin = ((p -1) * n) + 1;
if((p * n) % cm > n || (p * n) % cm == n){ //沒跨緩存
page = getFromCache(bucket, begin, n, page);
}else { //跨緩存
page = getFromCache(bucket - 1, begin, n - (p * n) % cm, page);
page = getFromCache(bucket, (bucket-1) * cm + 1, (p * n) % cm, page);
}
if((p * n) % cm > cm - n * x || (p * n) % cm == cm - n * x){
System.out.println("load cache");
cacheMemory.put(bucket + 1, loadCache(cm, bucket + 1));
}
System.out.println("page data : " + page);
}
/**
*
* @param bucket 第幾頁緩存
* @param begin 從哪個開始取
* @return
*/
private Map<Integer, Record> getFromCache(int bucket, int begin, int n, Map<Integer, Record> page){
Cache cache = cacheMemory.get(bucket);
for(int i = 0; i < n; i++){
Record r = cache.cache.get(begin + i);
page.put(begin + i, r);
}
return page;
}
/**
*
* @param cm 緩存大小
* @param bucket 第幾頁緩存
* @return
*/
private Cache loadCache(int cm, int bucket){
Cache cache = new Cache();
int deta = cm * (bucket-1) + 1;
for(int i = 0; i < cm; i++){
cache.cache.put(deta + i, dbData.get(deta + i));
}
return cache;
}
class Cache{
Map<Integer, Record> cache = new HashMap<Integer, Record>();
public String toString(){
StringBuffer sb = new StringBuffer();
for(Map.Entry entry : cache.entrySet()){
sb.append(entry.getKey() + ":" + entry.getValue() + ",");
}
return String.valueOf(sb);
}
}
class Record{
Object value;
Record(Object o){
value = o;
}
public String toString(){
return String.valueOf(value);
}
}
}
