Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.logicbus.kvalue.cache2.KValueCacheStore Maven / Gradle / Ivy
package com.logicbus.kvalue.cache2;
import com.alogic.cache.CacheObject;
import com.alogic.load.Loader;
import com.alogic.load.Store;
import com.alogic.xscript.Logiclet;
import com.alogic.xscript.LogicletContext;
import com.alogic.xscript.Script;
import com.alogic.xscript.doc.XsObject;
import com.alogic.xscript.doc.json.JsonObject;
import com.anysoft.util.*;
import com.logicbus.kvalue.context.KValueSource;
import com.logicbus.kvalue.core.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.HashMap;
import java.util.List;
/**
* 基于KValue的缓存Store实现
*
* @author yyduan
*
* @since 1.6.14.9 [20210507 duanyy]
*/
public class KValueCacheStore extends Loader.Sinkable implements Store{
/**
* 用于保存Hash类数据的表
*/
protected Table hashTable;
/**
* 用于保存id的表
*/
protected Table idTable;
/**
* 本缓存的id
*/
protected String id;
/**
* 是否在idTable中保存id列表
*/
protected boolean enableIdTable = false;
/**
* 加载事件脚本
*/
protected Logiclet onLoad = null;
/**
* 保存事件脚本
*/
protected Logiclet onSave = null;
protected Logiclet onDel = null;
protected String cacheObjectId = "$cache-object";
protected String objectId = "$cache-object-id";
protected boolean ttlUpdate = true;
/**
* 获取id
* @return id
*/
public String getId(){
return id;
}
@Override
public void configure(Properties p){
super.configure(p);
cacheObjectId = PropertiesConstants.getString(p,"cacheObjectId",cacheObjectId,true);
objectId = PropertiesConstants.getString(p,"objectId",objectId,true);
id = PropertiesConstants.getString(p, "id", "",true);
enableIdTable = PropertiesConstants.getBoolean(p, "table.id.enable", enableIdTable);
ttlUpdate = PropertiesConstants.getBoolean(p, "ttl.update", ttlUpdate);
String schema = PropertiesConstants.getString(p,"schema","redis");
String hashTableName = PropertiesConstants.getString(p,"table.hash","m");
String idtableName = PropertiesConstants.getString(p,"table.id","i");
Schema instance = KValueSource.getSchema(schema);
if (instance == null){
throw new BaseException("core.e1003","Can not find a kvalue schema named " + schema);
}
hashTable = instance.getTable(hashTableName);
if (hashTable == null){
throw new BaseException("core.e1003","Can not find a kvalue table named " + hashTableName);
}
idTable = instance.getTable(idtableName);
if (idTable == null){
throw new BaseException("core.e1003","Can not find a kavalue table named " + idtableName);
}
}
@Override
public void configure(Element e, Properties p) {
Properties props = new XmlElementProperties(e,p);
configure(props);
NodeList nodeList = XmlTools.getNodeListByPath(e, getSinkTag());
Factory> factory = new Factory>();
String scope = PropertiesConstants.getString(p, "ketty.scope", "runtime");
for (int i = 0 ;i < nodeList.getLength() ; i ++){
Node n = nodeList.item(i);
if (Node.ELEMENT_NODE != n.getNodeType()){
continue;
}
Element elem = (Element)n;
XmlElementProperties itemProps = new XmlElementProperties(elem,props);
String itemScope = PropertiesConstants.getString(itemProps,"scope","",true);
if (StringUtils.isNotEmpty(itemScope) && !itemScope.equals(scope)){
continue;
}
boolean enable = PropertiesConstants.getBoolean(itemProps,"enable",true,true);
if (!enable){
continue;
}
try {
Loader loader = factory.newInstance(elem, props, "module");
if (loader != null){
loaders.add(loader);
}
}catch (Exception ex){
LOG.error("Can not create loader from element:" + XmlTools.node2String(elem));
LOG.error(ExceptionUtils.getStackTrace(ex));
}
}
Element onLoadElem = XmlTools.getFirstElementByPath(e, "on-load");
if (onLoadElem != null){
onLoad = Script.create(onLoadElem, props);
}
Element onSaveElem = XmlTools.getFirstElementByPath(e, "on-save");
if (onSaveElem != null){
onSave = Script.create(onSaveElem, props);
}
Element onDelElem = XmlTools.getFirstElementByPath(e, "on-expire");
if (onDelElem != null){
onDel = Script.create(onDelElem, props);
}
}
/**
* 根据对象id生成在缓存中的id
* @param id 对象id
* @return 缓存中的id
*/
protected String getRowId(String id){
return this.getId() + '$' + id;
}
/**
* 根据id生成一个缓存对象(该对象不一定存在数据)
* @param id 对象id
* @return 缓存对象
*/
protected CacheObject getCacheObject(String id){
String rowId = getRowId(id);
HashRow hash = (HashRow) hashTable.select(rowId, true);
long ttl = this.getTTL();
if (ttl <= 0){
ttl = 30 * 60 * 1000L;
}
return new KValueCacheObject(id,hash,ttl,ttlUpdate);
}
@Override
public CacheObject load(String id, boolean cacheAllowed) {
if (noCache()){
return loadFromSink(id,cacheAllowed);
}else{
CacheObject found = loadFromSelf(id,cacheAllowed);
if (found == null){
if (hasSink()) {
synchronized (this) {
found = loadFromSelf(id, cacheAllowed);
if (found == null) {
found = loadFromSink(id, cacheAllowed);
if (found != null) {
onLoad(id, found);
cacheSave(id, found, true);
}
}
}
}
}
return found;
}
}
protected void onSave(String id, CacheObject cache) {
if (onSave != null){
LogicletContext logicletContext = new LogicletContext(Settings.get());
try {
logicletContext.setObject(cacheObjectId, cache);
XsObject doc = new JsonObject("root",new HashMap());
onSave.execute(doc,doc, logicletContext, null);
}catch (Exception ex){
LOG.info("Failed to execute onload script" + ExceptionUtils.getStackTrace(ex));
}finally{
logicletContext.removeObject(cacheObjectId);
}
}
}
protected void onLoad(String id, CacheObject cache) {
if (onLoad != null){
LogicletContext logicletContext = new LogicletContext(Settings.get());
try {
logicletContext.setObject(cacheObjectId, cache);
XsObject doc = new JsonObject("root",new HashMap());
onLoad.execute(doc,doc, logicletContext, null);
}catch (Exception ex){
LOG.info("Failed to execute onload script" + ExceptionUtils.getStackTrace(ex));
}finally{
logicletContext.removeObject(cacheObjectId);
}
}
}
protected void onDel(String id) {
if (onDel != null){
LogicletContext logicletContext = new LogicletContext(Settings.get());
try {
logicletContext.SetValue(objectId,id);
XsObject doc = new JsonObject("root",new HashMap());
onDel.execute(doc,doc, logicletContext, null);
}catch (Exception ex){
LOG.info("Failed to execute onDel script" + ExceptionUtils.getStackTrace(ex));
}
}
}
@Override
public CacheObject newObject(String id) {
return getCacheObject(id);
}
@Override
public void save(String id, CacheObject o, boolean overwrite) {
if (!noCache()) {
cacheSave(id, o, overwrite);
}
onSave(id,o);
}
public void cacheSave(String id, CacheObject o, boolean overwrite) {
if (o != null){
CacheObject kvObject = getCacheObject(id);
o.copyTo(kvObject);
if (enableIdTable){
SortedSetRow idRow = (SortedSetRow)idTable.select(getId(),true);
idRow.add(id, System.currentTimeMillis());
}
}
}
@Override
public void del(String id) {
CacheObject kvObject = getCacheObject(id);
if (kvObject.isValid()){
kvObject.expire();
onDel(id);
}
}
@Override
public void scan(List result, Pager pager) {
SortedSetRow idRow = (SortedSetRow)idTable.select(getId(),true);
long max = System.currentTimeMillis();
long min = max - getTTL();
List ids = idRow.rangeByScore(min, max, true, pager.getOffset(), pager.getLimit());
long all = idRow.count(min, max);
String keyword = pager.getKeyword();
int offset = pager.getOffset();
int limit = pager.getLimit();
int current = 0;
for (String id:ids){
boolean match = StringUtils.isEmpty(pager.getKeyword()) || id.contains(keyword);
if (match){
if (current >= offset && current < offset + limit){
result.add(id);
}
current ++;
}
}
pager.setAll(all).setTotal(current);
}
@Override
protected CacheObject loadFromSelf(String id, boolean cacheAllowed) {
if (cacheAllowed) {
CacheObject kvObject = getCacheObject(id);
if (kvObject.isValid()) {
if (enableIdTable) {
SortedSetRow idRow = (SortedSetRow) idTable.select(getId(), true);
idRow.add(id, System.currentTimeMillis());
}
return kvObject;
}
}
return null;
}
}