package com.taobao.tddl.executor.cursor.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.taobao.tddl.common.exception.TddlException;
import com.taobao.tddl.executor.codec.CodecFactory;
import com.taobao.tddl.executor.codec.RecordCodec;
import com.taobao.tddl.executor.common.DuplicateKVPair;
import com.taobao.tddl.executor.common.KVPair;
import com.taobao.tddl.executor.cursor.Cursor;
import com.taobao.tddl.executor.cursor.IInCursor;
import com.taobao.tddl.executor.cursor.SchematicCursor;
import com.taobao.tddl.executor.record.CloneableRecord;
import com.taobao.tddl.executor.record.FixedLengthRecord;
import com.taobao.tddl.executor.rowset.IRowSet;
import com.taobao.tddl.executor.utils.ExecUtils;
import com.taobao.tddl.optimizer.core.expression.IColumn;
import com.taobao.tddl.optimizer.core.expression.IFilter.OPERATION;
import com.taobao.tddl.optimizer.core.expression.IOrderBy;
/**
* 专门处理 id in (xx,xx,xx,xx)的cursor 接受一大批的id in请求,然后分批,batch的方式,调用mget拿到具体的值。
*
* @author whisper
*/
public class InCursor extends SchematicCursor implements IInCursor {
/**
* 单次请求,要设计一个限制,一次取出量不能太大。 TODO shenxun
* :目前实现,是限制性的,下次可以设计成分批取多次的模式,以平衡性能和内存消耗。
* 我一看一坨代码的东西就想哭啊。。妈的,所以简单实现一下,估计目前用不到这么复杂的算法
*/
public int sizeInOneGo = 4000;
IColumn c = null;
/**
* 需要查找的数据
*/
List<Object> valuesToFind = null;
OPERATION op = null; ;
RecordCodec keyCodec;
IRowSet current = null;
/**
* 一组返回的记录(size应该<=sizeInOneGo),分批取出
*/
List<DuplicateKVPair> pairToReturn;
/**
* 一组返回记录的指针
*/
Iterator<DuplicateKVPair> pairToReturnIterator;
/**
* 如果有相同的数据,那么一次取出后。 将这个值缓存在这里,下次可以取出。
*/
DuplicateKVPair duplicatePairCache = null;
public InCursor(Cursor cursor, List<IOrderBy> orderBys, IColumn c, List<Object> v, OPERATION op){
super(cursor, null, orderBys);
keyCodec = CodecFactory.getInstance(CodecFactory.FIXED_LENGTH)
.getCodec(Arrays.asList(ExecUtils.getColumnMeta(c)));
this.c = c;
// if (c.getDataType() == DATA_TYPE.DATE_VAL) {
// List<Object> vNew = new ArrayList<Object>(v.size());
// for (Object comp : v) {
// vNew.add(new Date((Long) comp));
// }
// v = vNew;
// }
this.valuesToFind = v;
this.op = op;
}
@Override
protected void init() throws TddlException {
super.init();
}
@Override
protected void checkInited() throws TddlException {
super.checkInited();
}
@Override
public boolean skipTo(CloneableRecord key) throws TddlException {
throw new IllegalArgumentException("should not be here");
}
@Override
public boolean skipTo(KVPair key) throws TddlException {
throw new IllegalArgumentException("should not be here");
}
public CloneableRecord getCloneableRecordOfKey(Object keyVal, RecordCodec keyCodec) {
List cs = new ArrayList(1);
cs.add(c);
FixedLengthRecord record = new FixedLengthRecord(ExecUtils.convertISelectablesToColumnMeta(cs));
record.put(this.c.getColumnName(), keyVal);
return record;
}
@Override
public IRowSet current() throws TddlException {
return current;
}
Iterator<KVPair> duplicatePairIterator = null;
@Override
public IRowSet next() throws TddlException {
if (valuesToFind == null) {
throw new IllegalArgumentException("value is null ");
}
if (pairToReturnIterator == null) {
// 还未初始化
List<CloneableRecord> list = new ArrayList<CloneableRecord>(valuesToFind.size());
for (Object valOne : valuesToFind) {
list.add(getCloneableRecordOfKey(valOne, keyCodec));
}
pairToReturn = cursor.mgetWithDuplicateList(list, false, true);
pairToReturnIterator = pairToReturn.iterator();
}
/**
* 需要查找数据的iterator,用来记录指针
*/
// Iterator<Comparable> valuesToFindIterator = valuesToFind.iterator();
/*
* 简单来说,就是根据sizeInOneGo,从values里面取出指定多的数据。 然后运行一次mget,将结果缓存在当前cursor里面。
* 提供给外部进行next调用,应该之需要支持next和current吧。暂时 因为数据可能包含多个,比如1->0,1->2 ,
* 1->3,2->0,2->1这样的数据,应该先将1对应的所有数据全部取尽,再去取第二个。
*/
if (duplicatePairCache == null) {// 两中情况,一种是duplicate值为空,这时候应该尝试让pairToReturnIterator指针下移。
// 如pairToReturnIterator也没有数据。则结果集内没有数据,直接返回空。
if (pairToReturnIterator.hasNext()) {
duplicatePairCache = pairToReturnIterator.next();
} else {
// while end/当前一批没有可以取的数据了,未来可以改成多层循环,一次batch取一小部分。
setCurrent(null);
return null;
}
}
// 取当前值,可能是重复数据的第一个数据,或者也可能是重复数据中,被当前duplicatePairCache 缓存的数据
setCurrent(duplicatePairCache.currentKey);
// 指针下移
duplicatePairCache = duplicatePairCache.next;
return current;
}
public void setCurrent(IRowSet kvPair) {
if (kvPair != null) {
current = kvPair;
}
}
/*
* // 循环遍历,直到取出一个结果或取尽为止 DuplicateKVPair duplicate =
* pairToReturnIterator.next(); if (duplicate == null) { setCurrent(null);
* return null; } else { if (duplicatePairIterator == null) {//
* 第一次进入当前可重复KVPair内。初始化iterator duplicatePairIterator =
* duplicate.getKvPairs() .iterator(); } if
* (duplicatePairIterator.hasNext()) {// 当前DuplicatePair // 有重复数据(或第一个数据)
* KVPair ret = duplicatePairIterator.next(); setCurrent(ret); return ret; }
* else { duplicatePairIterator = null; } } (non-Javadoc)
* @see com.taobao.ustore.common.inner.AbstractCursor#prev()
*/
@Override
public boolean delete() throws TddlException {
throw new IllegalArgumentException("should not be here");
}
@Override
public Map<CloneableRecord, DuplicateKVPair> mgetWithDuplicate(List<CloneableRecord> keys, boolean prefixMatch,
boolean keyFilterOrValueFilter) throws TddlException {
return parentCursorMgetWithDuplicate(keys, prefixMatch, keyFilterOrValueFilter);
}
}