package com.easyooo.framework.cache.transaction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import com.easyooo.framework.cache.CacheException;
import com.easyooo.framework.cache.CacheLevel;
import com.easyooo.framework.cache.storage.ICache;
import com.easyooo.framework.cache.storage.JVMCache;
import com.easyooo.framework.cache.transaction.Command.Operation;
import com.easyooo.framework.support.transaction.RemoteSenderMorly;
import com.easyooo.framework.support.transaction.SimpleBufferedSender;
/**
* 缓存事务实现,在实际缓存操作类之前注入该类,在每次操作缓存时将缓存数据刷入内存,
* 而不是直接发送到缓存数据中心,可利用该类实现,在数据库事务提交完成之后,再提交缓存的数据更新,
* 从而实现一个简单的 "1pc" 事务
*
* @author Killer
*/
public class BufferedCache implements ICache {
private ICache delegate;
/**
* 确保只有这一个实例,如果产生多个实例,则多个实例间的操作是隔离的
* 提交也会分多次提交
*/
private static SimpleBufferedSender<Command> commandSender ;
private final CacheLevel level;
private BufferedCollectionUtil bufferUtil = new BufferedCollectionUtil();
public BufferedCache(ICache delegate, RemoteSenderMorly<Command> remoteSender, CacheLevel level){
super();
setDelegate(delegate);
this.level = level;
if(commandSender == null){
commandSender = new SimpleBufferedSender<>(remoteSender);
}
}
@Override
public boolean set(String cacheKey, String value) throws CacheException {
return putQueue(Command.newSetCommand(cacheKey, value, level));
}
@Override
public boolean mod(String cacheKey, String value) throws CacheException {
return putQueue(Command.newModCommand(cacheKey, value, level));
}
@Override
public Long del(String cacheKey) throws CacheException {
Boolean bool = putQueue(Command.newDelCommand(cacheKey, level));
return bool ? 1L : 0L;
}
@Override
public String get(String cacheKey) throws CacheException {
Collection<Command> bufferCmds = commandSender.getOriginalBufferList();
Command command = bufferUtil.getLastFromBufferd(bufferCmds, cacheKey, level);
// 缓冲区不存在命令,则交给委托处理
if(command == null){
return delegate.get(cacheKey);
}
// 如果是删除命令,则返回null
if(command.getOp() == Operation.DEL){
return null;
}
// 如果是SET或MOD命令则返回最新的值
return command.getCacheValue();
}
@Override
public List<String> gets(String... cacheKey) throws CacheException {
String[] target = new String[cacheKey.length];
Collection<Command> bufferCmds = commandSender.getOriginalBufferList();
List<Command> commands = bufferUtil.getLastFromBufferd(bufferCmds,level, cacheKey);
// 提取不在缓冲区的命令
// delegateIndex 索引槽用于target返回数据占位符
// 如果缓冲区不存在命令,加入委托集
List<String> delegateCacheKey = new ArrayList<String>();
List<Integer> delegateIndex = new ArrayList<Integer>();
for (int i = 0; i < cacheKey.length; i++) {
String key = cacheKey[i];
Command cmd = commands.get(i);
if(null == cmd) {
delegateCacheKey.add(key);
delegateIndex.add(i);
target[i] = null;
} else {
// 如果是删除命令,则返回null
target[i] = (cmd.getOp() == Operation.DEL) ? null : cmd.getCacheValue();
}
}
// 缓冲区不存在的命令,则交给委托处理
if(delegateCacheKey.size() > 0){
List<String> parts = delegate.gets(delegateCacheKey
.toArray(new String[] {}));
// replace target null value
for (int i = 0; i < delegateCacheKey.size(); i++) {
target[delegateIndex.get(i)] = parts.get(i);
}
}
return Arrays.asList(target);
}
@Override
public boolean sets(String... keyvalues) throws CacheException {
return putQueue(Command.newSetsCommand(keyvalues, level));
}
@Override
public Long addMembers(String groupKey, String... entityCacheKeys)
throws CacheException {
putQueue(Command.newAddMembersCommand(groupKey, entityCacheKeys, level));
return (long)entityCacheKeys.length;
}
@Override
public Long delMembers(String groupKey, String... entityCacheKeys)
throws CacheException {
putQueue(Command.newDelMembersCommand(groupKey, entityCacheKeys, level));
return (long)entityCacheKeys.length;
}
@Override
public Set<String> getMembers(String groupKey) throws CacheException {
// delegate get all members
Set<String> members = delegate.getMembers(groupKey);
final int rows = (members == null) ? -1 : members.size();
// if members is null
if(rows < 0){
members = JVMCache.newMemberContainer();
}
// replace part members
Collection<Command> bufferCmds = commandSender.getOriginalBufferList();
bufferUtil.replaceMembersFromBufferd(bufferCmds, members, groupKey);
if(rows < 0 && members.size() == 0){
return null;
}
return members;
}
@Override
public int getSize() {
return this.delegate.getSize();
}
protected void setDelegate(ICache delegate) {
if(delegate != null && delegate != this){
this.delegate = delegate;
}
}
/**
* 将命令放入队列
*/
private boolean putQueue(Command cmd)throws CacheException{
try {
return commandSender.send(cmd);
} catch (Exception e) {
throw new CacheException(e);
}
}
}