package com.ctriposs.tsdb.iterator; import java.io.IOException; import java.util.Collections; import java.util.Map.Entry; import java.util.concurrent.ConcurrentSkipListSet; import com.ctriposs.tsdb.ISeekIterator; import com.ctriposs.tsdb.InternalKey; import com.ctriposs.tsdb.manage.FileManager; import com.ctriposs.tsdb.util.ByteUtil; public class SeekIteratorAdapter implements ISeekIterator<InternalKey, byte[]>{ private ConcurrentSkipListSet<ISeekIterator<InternalKey, byte[]>> itSet; private Direction direction; private ISeekIterator<InternalKey, byte[]> curIt; private FileManager fileManager; private long curSeekTime; private int curSeekCode; public SeekIteratorAdapter(FileManager fileManager, ISeekIterator<InternalKey, byte[]>... its) { this.itSet = new ConcurrentSkipListSet<ISeekIterator<InternalKey, byte[]>>(fileManager.getIteratorComparator()); addIterator(its); this.fileManager = fileManager; this.direction = Direction.forward; this.curIt = null; } public void addIterator(ISeekIterator<InternalKey, byte[]>... its) { Collections.addAll(itSet, its); } @Override public boolean hasNext() { boolean result = false; if(curIt!=null&&curIt.hasNext()){ result = true; }else{ if(curIt != null){ curIt.next(); } if(itSet != null) { for (ISeekIterator<InternalKey, byte[]> it : itSet) { if(it.hasNext()) { result = true; break; } } } if(result){ findSmallest(); } } return result; } @Override public boolean hasPrev() { boolean result = false; if(curIt!=null&&curIt.hasPrev()){ result = true; }else{ if(itSet != null) { for (ISeekIterator<InternalKey, byte[]> it : itSet) { if(it.hasPrev()) { result = true; break; } } } if(result){ findLargest(); } } return result; } @Override public Entry<InternalKey, byte[]> next() { if (direction != Direction.forward) { for (ISeekIterator<InternalKey, byte[]> it : itSet) { if (it != curIt) { try { it.seek(curSeekCode,curSeekTime); } catch (IOException e) { throw new RuntimeException(e); } } } findSmallest(); direction = Direction.forward; } Entry<InternalKey, byte[]> entry = curIt.next(); findSmallest(); if(entry != null){ curSeekTime = entry.getKey().getTime(); } return entry; } @Override public Entry<InternalKey, byte[]> prev() { if(direction != Direction.reverse){ for(ISeekIterator<InternalKey, byte[]> it:itSet){ if(curIt != it){ try { it.seek(curSeekCode,curSeekTime); } catch (IOException e) { throw new RuntimeException(e); } } } findLargest(); direction = Direction.reverse; } Entry<InternalKey, byte[]> entry = curIt.prev(); findLargest(); if(entry != null){ curSeekTime = entry.getKey().getTime(); } return entry; } @Override public void seek(String table, String column, long time) throws IOException { seek(ByteUtil.ToInt(fileManager.getCode(table),fileManager.getCode(column)), time); } @Override public void seek(int code, long time) throws IOException { this.curSeekCode = code; this.curSeekTime = time; if(!itSet.isEmpty()){ for(ISeekIterator<InternalKey, byte[]> it:itSet){ it.seek(curSeekCode,time); } findSmallest(); direction = Direction.forward; } } private void findSmallest(){ if(!itSet.isEmpty()){ ISeekIterator<InternalKey, byte[]> smallest = null; for(ISeekIterator<InternalKey, byte[]> it:itSet){ if(it.valid()){ if(smallest == null){ smallest = it; }else if(fileManager.compare(smallest.key(), it.key())>0){ smallest = it; }else if(fileManager.compare(smallest.key(), it.key())==0){ while(it.hasNext()){ it.next(); int diff = fileManager.compare(smallest.key(),it.key()); if(0==diff){ continue; }else{ break; } } } } } if(smallest != null){ curIt = smallest; } } } private void findLargest(){ if(!itSet.isEmpty()){ ISeekIterator<InternalKey, byte[]> largest = null; for(ISeekIterator<InternalKey, byte[]> it:itSet){ if(it.valid()){ if(largest == null){ largest = it; }else if(fileManager.compare(largest.key(), it.key())<0){ largest = it; }else if(fileManager.compare(largest.key(), it.key())==0){ while(it.hasPrev()){ it.prev(); int diff = fileManager.compare(largest.key(),it.key()); if(0==diff){ continue; }else{ break; } } } } } if(largest != null){ curIt = largest; } } } @Override public String table() { if(curIt != null){ return curIt.table(); } return null; } @Override public String column() { if(curIt != null){ return curIt.column(); } return null; } @Override public long time() { if(curIt != null){ return curIt.key().getTime(); } return 0; } @Override public byte[] value() throws IOException { if(curIt != null){ return curIt.value(); } return null; } @Override public boolean valid() { if(curIt==null){ return false; }else{ return curIt.valid(); } } @Override public void close() throws IOException{ if(!itSet.isEmpty()){ for(ISeekIterator<InternalKey, byte[]> it:itSet){ it.close(); } } } @Override public InternalKey key() { if(curIt != null){ return curIt.key(); } return null; } @Override public void remove() { throw new UnsupportedOperationException("unsupport remove operation!"); } enum Direction{ forward,reverse } @Override public long priority() { return 0; } }