package com.taobao.tddl.executor.cursor.impl; import java.util.ArrayList; import java.util.List; import java.util.Map; import com.taobao.tddl.common.exception.TddlException; import com.taobao.tddl.common.utils.GeneralUtil; import com.taobao.tddl.executor.common.DuplicateKVPair; import com.taobao.tddl.executor.cursor.Cursor; import com.taobao.tddl.executor.cursor.ISchematicCursor; import com.taobao.tddl.executor.record.CloneableRecord; import com.taobao.tddl.executor.rowset.IRowSet; import com.taobao.tddl.executor.utils.ExecUtils; /** * n个cursor的归并排序,假设子cursor都是有序的 * * @author mengshi.sunmengshi 2013-12-3 上午10:57:02 * @since 5.0.0 */ public class MergeSortedCursors extends SortCursor { private ValueMappingIRowSetConvertor valueMappingIRowSetConvertor; private final List<ISchematicCursor> cursors; /** * 保存每个cursor当前的值得wrapper */ private List<IRowSet> values; private boolean templateIsLeft = true; public MergeSortedCursors(List<ISchematicCursor> cursors, boolean duplicated) throws TddlException{ super(cursors.get(0), null); this.cursors = cursors; this.allowDuplicated = duplicated; values = new ArrayList(cursors.size()); this.orderBys = cursors.get(0).getOrderBy(); } public MergeSortedCursors(ISchematicCursor cursor, boolean duplicated) throws TddlException{ super(cursor, null); List<ISchematicCursor> cursors = new ArrayList(1); cursors.add(cursor); this.cursors = cursors; this.allowDuplicated = duplicated; values = new ArrayList(cursors.size()); } @Override public void beforeFirst() throws TddlException { inited = false; values.clear(); values = new ArrayList(cursors.size()); for (Cursor cursor : cursors) { cursor.beforeFirst(); } } boolean allowDuplicated = false; IRowSet current = null; boolean inited = false; @Override public void init() throws TddlException { if (inited) { return; } inited = true; for (int i = 0; i < cursors.size(); i++) { IRowSet row = cursors.get(i).next(); row = convertToIRowSet(row, i == 0); values.add(row); } } IRowSet currentMaxOrMin = null; /** * values中存着每个cursor的当前值 每次调用next,从values中找出最小的值,并且将对应的cursor前移 将新值存到values中 * 如果去重,需要将重复的值略过 */ @Override public IRowSet next() throws TddlException { init(); int indexOfCurrentMaxOrMin = 0; currentMaxOrMin = null; for (int i = 0; i < this.values.size(); i++) { IRowSet row = this.values.get(i); if (row == null) { continue; } if (currentMaxOrMin == null) { currentMaxOrMin = row; indexOfCurrentMaxOrMin = i; continue; } super.initComparator(orderBys, row.getParentCursorMeta()); int n = kvPairComparator.compare(row, currentMaxOrMin); if (n < 0) { currentMaxOrMin = row; indexOfCurrentMaxOrMin = i; } else if (n == 0) { if (!this.allowDuplicated) { // 去重 // 把其他cursor中重复的记录消耗光 IRowSet rowToRemoveDuplicate = currentMaxOrMin; while (true) { rowToRemoveDuplicate = this.cursors.get(i).next(); if (rowToRemoveDuplicate == null) { break; } rowToRemoveDuplicate = convertToIRowSet(rowToRemoveDuplicate, i == 0); if (kvPairComparator.compare(rowToRemoveDuplicate, currentMaxOrMin) != 0) { break; } } this.values.set(i, rowToRemoveDuplicate); } } } if (currentMaxOrMin != null) { currentMaxOrMin = ExecUtils.fromIRowSetToArrayRowSet(currentMaxOrMin); IRowSet rowToRemoveDuplicate = currentMaxOrMin; // 选中的cursor消费一行记录,往前移动,如果有需要,还要去重 while (true) { rowToRemoveDuplicate = this.cursors.get(indexOfCurrentMaxOrMin).next(); if (rowToRemoveDuplicate == null) { break; } rowToRemoveDuplicate = convertToIRowSet(rowToRemoveDuplicate, indexOfCurrentMaxOrMin == 0); if (this.allowDuplicated) { break; } super.initComparator(orderBys, rowToRemoveDuplicate.getParentCursorMeta()); if (kvPairComparator.compare(rowToRemoveDuplicate, currentMaxOrMin) != 0) { break; } } this.values.set(indexOfCurrentMaxOrMin, rowToRemoveDuplicate); } setCurrent(currentMaxOrMin); return currentMaxOrMin; } private IRowSet convertToIRowSet(IRowSet rowSet, boolean left) { if (rowSet == null) { return null; } if (valueMappingIRowSetConvertor == null) {// 认为是初始化 valueMappingIRowSetConvertor = new ValueMappingIRowSetConvertor(); valueMappingIRowSetConvertor.wrapValueMappingIRowSetIfNeed(rowSet); valueMappingIRowSetConvertor.reset(); templateIsLeft = left; } if (templateIsLeft == left) { // template is left and current is left // template is right and current is right return rowSet; } else { // template is left but current is right // or template is right but current is left return valueMappingIRowSetConvertor.wrapValueMappingIRowSetIfNeed(rowSet); } } private void setCurrent(IRowSet current) { this.current = current; } @Override public IRowSet current() throws TddlException { return current; } @Override public IRowSet first() throws TddlException { for (int i = 0; i < this.cursors.size(); i++) { cursors.get(i).beforeFirst(); } this.values.clear(); this.inited = false; this.init(); return next(); } @Override public void put(CloneableRecord key, CloneableRecord value) throws TddlException { throw new UnsupportedOperationException("should not be here"); } @Override public Cursor getCursor() { return cursor; } @Override public Map<CloneableRecord, DuplicateKVPair> mgetWithDuplicate(List<CloneableRecord> keys, boolean prefixMatch, boolean keyFilterOrValueFilter) throws TddlException { throw new UnsupportedOperationException("should not be here"); } @Override public List<DuplicateKVPair> mgetWithDuplicateList(List<CloneableRecord> keys, boolean prefixMatch, boolean keyFilterOrValueFilter) throws TddlException { throw new UnsupportedOperationException("should not be here"); } @Override public String toStringWithInden(int inden) { String tabTittle = GeneralUtil.getTab(inden); String tabContent = GeneralUtil.getTab(inden + 1); StringBuilder sb = new StringBuilder(); GeneralUtil.printlnToStringBuilder(sb, tabTittle + "MergeSortedCursor "); GeneralUtil.printAFieldToStringBuilder(sb, "orderBy", this.orderBys, tabContent); for (Cursor sub : this.cursors) { sb.append(sub.toStringWithInden(inden + 1)); } return sb.toString(); } @Override public List<TddlException> close(List<TddlException> exs) { for (Cursor c : this.cursors) { if (c != null) { exs = c.close(exs); } } return exs; } @Override public String toString() { return toStringWithInden(0); } }