package com.alibaba.doris.dataserver.store.log.db; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.doris.common.data.Pair; import com.alibaba.doris.dataserver.store.ClosableIterator; import com.alibaba.doris.dataserver.store.log.db.impl.DefaultLogClumpImpl; import com.alibaba.doris.dataserver.store.log.entry.ClumpHeadEntry; import com.alibaba.doris.dataserver.store.log.entry.LogEntry; import com.alibaba.doris.dataserver.store.log.utils.LogFileUtil; /** * @author ajun Email:jack.yuj@alibaba-inc.com */ public class LogClumpManager { public LogClumpManager(ClumpConfigure config) { avaliableLogClumps = new TreeSet<LogClump>(new Comparator<LogClump>() { public int compare(LogClump o1, LogClump o2) { return o1.getNo() - o2.getNo(); } }); this.config = config; listAvaliableLogClumps(); } public LogClump getLogClump() { if (null == currentClump) { if (avaliableLogClumps.size() > 0) { currentClump = avaliableLogClumps.last(); } else { currentClump = new DefaultLogClumpImpl(getClumpConfigure(), getLastFileName()); avaliableLogClumps.add(currentClump); } return currentClump; } if (currentClump.size() > (config.getMaxFileSize() - 1024)) { currentClump = new DefaultLogClumpImpl(getClumpConfigure(), getNextFileName()); avaliableLogClumps.add(currentClump); } return currentClump; } /** * 列出所有当前可见的Log Clump * * @return */ public synchronized LogClump[] listAvaliableLogClumps() { avaliableLogClumps.clear(); String[] clumpNames = LogFileUtil.listAllLogClumpFileName(getClumpConfigure().getPath()); if (null != clumpNames) { List<LogClump> clumps = new ArrayList<LogClump>(clumpNames.length); for (String name : clumpNames) { clumps.add(new DefaultLogClumpImpl(getClumpConfigure(), name)); } avaliableLogClumps.addAll(clumps); } LogClump[] clumpArray = new LogClump[avaliableLogClumps.size()]; return avaliableLogClumps.toArray(clumpArray); } private LogClump[] listAllLogClumps() { String[] clumpNames = LogFileUtil.listAllLogClumpFileName(getClumpConfigure().getPath()); if (null != clumpNames && clumpNames.length > 0) { LogClump[] clumps = new LogClump[clumpNames.length]; for (int i = 0; i < clumpNames.length; i++) { clumps[i] = new DefaultLogClumpImpl(getClumpConfigure(), clumpNames[i]); } return clumps; } return EMPTY_LOGCLUMP_ARRAY; } /** * 列出所有LogClumps,剔除当前正在处理的LogClump; * * @return */ public LogClump[] listAllNonProcessingLogClumps() { String[] clumpNames = LogFileUtil.listAllLogClumpFileName(getClumpConfigure().getPath()); if (null != clumpNames && clumpNames.length > 1) { LogClump[] clumps = new LogClump[clumpNames.length]; String currentLogClumpName = this.currentClump.getName(); for (int i = 0; i < clumpNames.length; i++) { if (!clumpNames[i].equals(currentLogClumpName)) { clumps[i] = new DefaultLogClumpImpl(getClumpConfigure(), clumpNames[i]); } } return clumps; } return EMPTY_LOGCLUMP_ARRAY; } /** * 关闭并释放所有的资源 */ public synchronized void releaseAllResources() { // for (LogClump clump : avaliableLogClumps) { // if (clump.isOpen()) { // clump.close(); // } // } } private String getNextFileName() { synchronized (this) { LogClump lastClump = avaliableLogClumps.last(); int clumpNo = 0; if (null != lastClump) { clumpNo = lastClump.getNo() + 1; } return LogFileUtil.generateClumpName(clumpNo); } } private String getLastFileName() { synchronized (this) { int clumpNo = 0; if (avaliableLogClumps.size() > 0) { LogClump lastClump = avaliableLogClumps.last(); if (null != lastClump) { return lastClump.getName(); } } else { clumpNo = LogFileUtil.getMaxClumpNo(config.getPath()); } return LogFileUtil.generateClumpName(clumpNo); } } protected ClumpConfigure getClumpConfigure() { return config; } public boolean deleteLogClump(LogClump logClump) { ClumpHeadEntry head = logClump.getClumpHeadEntry(); if (head.getVnodeNum() > 0) { return false; } LogFileUtil.deleteClumpFile(getClumpConfigure().getPath(), logClump.getName()); return true; } public synchronized boolean deleteLogClumps(List<Integer> vnodeList) { Iterator<LogClump> itr = avaliableLogClumps.iterator(); boolean isSuccess = false; ByteBuffer buffer = ByteBuffer.allocate(this.config.getWriteBufferSize()); while (itr.hasNext()) { LogClump clump = itr.next(); WriteWindow writeWindow = clump.getWriteWindow(); try { if (deleteLogClumpDataByVnodes(clump, vnodeList, buffer)) { itr.remove(); isSuccess = true; } } catch (WriteWindowClosedException e) { // 如果出现WindowClosedException??? writeWindow = clump.getWriteWindow(); if (deleteLogClumpDataByVnodes(clump, vnodeList, buffer)) { itr.remove(); isSuccess = true; } } finally { if (clump != currentClump) { writeWindow.close(); } } } return isSuccess; } /** * @param clump * @param vnodeList * @return true:表示logclump对应的文件已经被删除; */ public boolean deleteLogClumpDataByVnodes(LogClump clump, List<Integer> vnodeList, ByteBuffer buffer) { if (null == clump) { return false; } WriteWindow writeWindow = clump.getWriteWindow(buffer); try { if (writeWindow.deleteByVnodes(vnodeList)) { if (clump != currentClump) { writeWindow.close(); if (deleteLogClump(clump)) { if (logger.isDebugEnabled()) { logger.debug("Delete log clump file. Clump name is " + clump.getName()); } return true; } } else { return true; } } } finally { writeWindow.close(); } return false; } public ClosableIterator<Pair> iterator() { return new LogClumpsIterator(listAllLogClumps()); } public ClosableIterator<Pair> iterator(final List<Integer> vnodeList) { final Map<Integer, Integer> vnodeMap = new HashMap<Integer, Integer>(vnodeList.size()); for (Integer vnode : vnodeList) { vnodeMap.put(vnode, vnode); } LogClump[] clumpList = listLogClumpByVnodes(vnodeList); return new LogClumpsIterator(clumpList) { @Override protected boolean doFilter(LogEntry logEntry) { if (null == logEntry) { return false; } return vnodeMap.get(logEntry.getVnode()) != null; } }; } public LogClump[] listLogClumpByVnodes(List<Integer> vnodeList) { LogClump[] clumpArray = listAllLogClumps(); List<LogClump> needIteratorClumpArray = new ArrayList<LogClump>(vnodeList.size()); for (LogClump clump : clumpArray) { ClumpHeadEntry headEntry = clump.getClumpHeadEntry(); Iterator<Integer> nodeItr = headEntry.getVnodes(); while (nodeItr.hasNext()) { if (vnodeList.contains(nodeItr.next())) { needIteratorClumpArray.add(clump); break; } } } return needIteratorClumpArray.toArray(new LogClump[needIteratorClumpArray.size()]); } private LogClump currentClump; private ClumpConfigure config; private SortedSet<LogClump> avaliableLogClumps; private static final LogClump[] EMPTY_LOGCLUMP_ARRAY = new LogClump[0]; private static final Logger logger = LoggerFactory.getLogger(LogClumpManager.class); }