package com.sleepycat.je.log; import java.io.IOException; import java.nio.ByteBuffer; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; import com.sleepycat.je.DatabaseException; import com.sleepycat.je.config.EnvironmentParams; import com.sleepycat.je.dbi.EnvironmentImpl; import com.sleepycat.je.utilint.DbLsn; import de.ovgu.cide.jakutil.*; /** * The StatsFileReader generates stats about the log entries read, such as the * count of each type of entry, the number of bytes, minimum and maximum sized * log entry. */ public class StatsFileReader extends DumpFileReader { private Map entryInfoMap; private long totalLogBytes; private long totalCount; private ArrayList ckptList; private CheckpointCounter ckptCounter; private long firstLsnRead; /** * Create this reader to start at a given LSN. */ public StatsFileReader( EnvironmentImpl env, int readBufferSize, long startLsn, long finishLsn, String entryTypes, String txnIds, boolean verbose) throws IOException, DatabaseException { super(env,readBufferSize,startLsn,finishLsn,entryTypes,txnIds,verbose); entryInfoMap=new TreeMap(new LogEntryTypeComparator()); totalLogBytes=0; totalCount=0; ckptCounter=new CheckpointCounter(); ckptList=new ArrayList(); if (verbose) { ckptList.add(ckptCounter); } } /** * This reader collects stats about the log entry. */ protected boolean processEntry( ByteBuffer entryBuffer) throws DatabaseException { LogEntryType lastEntryType=LogEntryType.findType(currentEntryTypeNum,currentEntryTypeVersion); entryBuffer.position(entryBuffer.position() + currentEntrySize); EntryInfo info=(EntryInfo)entryInfoMap.get(lastEntryType); if (info == null) { info=new EntryInfo(); entryInfoMap.put(lastEntryType,info); } info.count++; totalCount++; if (LogEntryType.isProvisional(currentEntryTypeVersion)) { info.provisionalCount++; } int size=currentEntrySize + LogManager.HEADER_BYTES; info.totalBytes+=size; totalLogBytes+=size; if ((info.minBytes == 0) || (info.minBytes > size)) { info.minBytes=size; } if (info.maxBytes < size) { info.maxBytes=size; } if (verbose) { if (firstLsnRead == DbLsn.NULL_LSN) { firstLsnRead=getLastLsn(); } if (currentEntryTypeNum == LogEntryType.LOG_CKPT_END.getTypeNum()) { ckptCounter.endCkptLsn=getLastLsn(); ckptCounter=new CheckpointCounter(); ckptList.add(ckptCounter); } else { ckptCounter.increment(this,currentEntryTypeNum); } } return true; } public void summarize(){ System.out.println("Log statistics:"); Iterator iter=entryInfoMap.entrySet().iterator(); NumberFormat form=NumberFormat.getIntegerInstance(); NumberFormat percentForm=NumberFormat.getInstance(); percentForm.setMaximumFractionDigits(1); System.out.println(pad("type") + pad("total") + pad("provisional")+ pad("total")+ pad("min")+ pad("max")+ pad("avg")+ pad("entries")); System.out.println(pad("") + pad("count") + pad("count")+ pad("bytes")+ pad("bytes")+ pad("bytes")+ pad("bytes")+ pad("as % of log")); long realTotalBytes=0; while (iter.hasNext()) { Map.Entry m=(Map.Entry)iter.next(); EntryInfo info=(EntryInfo)m.getValue(); StringBuffer sb=new StringBuffer(); LogEntryType entryType=(LogEntryType)m.getKey(); sb.append(pad(entryType.toString())); sb.append(pad(form.format(info.count))); sb.append(pad(form.format(info.provisionalCount))); sb.append(pad(form.format(info.totalBytes))); sb.append(pad(form.format(info.minBytes))); sb.append(pad(form.format(info.maxBytes))); sb.append(pad(form.format((long)(info.totalBytes / info.count)))); double entryPercent=((double)(info.totalBytes * 100) / totalLogBytes); sb.append(pad(percentForm.format(entryPercent))); System.out.println(sb.toString()); if (entryType == LogEntryType.LOG_LN_TRANSACTIONAL) { int overhead=LogManager.HEADER_BYTES + 46; realTotalBytes+=info.totalBytes - (info.count * overhead); } if (entryType == LogEntryType.LOG_LN) { int overhead=LogManager.HEADER_BYTES + 21; realTotalBytes+=info.totalBytes - (info.count * overhead); } } StringBuffer sb=new StringBuffer(); sb.append(pad("key/data")); sb.append(pad("")); sb.append(pad("")); sb.append(pad(form.format(realTotalBytes))); sb.append(pad("")); sb.append(pad("")); sb.append(pad("")); String realSize="(" + percentForm.format((double)(realTotalBytes * 100) / totalLogBytes) + ")"; sb.append(pad(realSize)); System.out.println(sb.toString()); System.out.println("\nTotal bytes in portion of log read: " + form.format(totalLogBytes)); System.out.println("Total number of entries: " + form.format(totalCount)); if (verbose) { summarizeCheckpointInfo(); } } private String pad( String result){ int spaces=15 - result.length(); StringBuffer sb=new StringBuffer(); for (int i=0; i < spaces; i++) { sb.append(" "); } sb.append(result); return sb.toString(); } private void summarizeCheckpointInfo(){ System.out.println("\nPer checkpoint interval info:"); System.out.println(pad("lnTxn") + pad("ln") + pad("mapLNTxn")+ pad("mapLN")+ pad("end-end")+ pad("end-start")+ pad("start-end")+ pad("maxLNReplay")+ pad("ckptEnd")); long logFileMax; try { logFileMax=env.getConfigManager().getLong(EnvironmentParams.LOG_FILE_MAX); } catch ( DatabaseException e) { e.printStackTrace(); return; } Iterator iter=ckptList.iterator(); CheckpointCounter prevCounter=null; NumberFormat form=NumberFormat.getInstance(); while (iter.hasNext()) { CheckpointCounter c=(CheckpointCounter)iter.next(); StringBuffer sb=new StringBuffer(); int maxTxnLNs=c.preStartLNTxnCount + c.postStartLNTxnCount; sb.append(pad(form.format(maxTxnLNs))); int maxLNs=c.preStartLNCount + c.postStartLNCount; sb.append(pad(form.format(maxLNs))); sb.append(pad(form.format(c.preStartMapLNTxnCount + c.postStartMapLNTxnCount))); sb.append(pad(form.format(c.preStartMapLNCount + c.postStartMapLNCount))); long end=(c.endCkptLsn == DbLsn.NULL_LSN) ? getLastLsn() : c.endCkptLsn; long endToEndDistance=0; FileManager fileManager=env.getFileManager(); if (prevCounter == null) { endToEndDistance=DbLsn.getWithCleaningDistance(end,fileManager,firstLsnRead,logFileMax); } else { endToEndDistance=DbLsn.getWithCleaningDistance(end,fileManager,prevCounter.endCkptLsn,logFileMax); } sb.append(pad(form.format(endToEndDistance))); long start=(c.startCkptLsn == DbLsn.NULL_LSN) ? getLastLsn() : c.startCkptLsn; long endToStartDistance=0; if (prevCounter == null) { endToStartDistance=DbLsn.getWithCleaningDistance(start,fileManager,firstLsnRead,logFileMax); } else { endToStartDistance=DbLsn.getWithCleaningDistance(start,fileManager,prevCounter.endCkptLsn,logFileMax); } sb.append(pad(form.format(endToStartDistance))); long startToEndDistance=0; if ((c.startCkptLsn != DbLsn.NULL_LSN) && (c.endCkptLsn != DbLsn.NULL_LSN)) { startToEndDistance=DbLsn.getWithCleaningDistance(c.endCkptLsn,fileManager,c.startCkptLsn,logFileMax); } sb.append(pad(form.format(startToEndDistance))); int maxReplay=maxLNs + maxTxnLNs; if (prevCounter != null) { maxReplay+=prevCounter.postStartLNTxnCount; maxReplay+=prevCounter.postStartLNCount; } sb.append(pad(form.format(maxReplay))); if (c.endCkptLsn == DbLsn.NULL_LSN) { sb.append(" ").append(DbLsn.getNoFormatString(getLastLsn())); } else { sb.append(" ").append(DbLsn.getNoFormatString(c.endCkptLsn)); } System.out.println(sb.toString()); prevCounter=c; } } static class EntryInfo { public int count; public int provisionalCount; public long totalBytes; public int minBytes; public int maxBytes; EntryInfo(){ count=0; provisionalCount=0; totalBytes=0; minBytes=0; maxBytes=0; } } static class LogEntryTypeComparator implements Comparator { public int compare( Object o1, Object o2){ if (o1 == null) { return -1; } if (o2 == null) { return 1; } if (o1 instanceof LogEntryType && o2 instanceof LogEntryType) { Byte t1=new Byte(((LogEntryType)o1).getTypeNum()); Byte t2=new Byte(((LogEntryType)o2).getTypeNum()); return t1.compareTo(t2); } else { throw new IllegalArgumentException("non LogEntryType passed to LogEntryType.compare"); } } } static class CheckpointCounter { public long startCkptLsn=DbLsn.NULL_LSN; public long endCkptLsn=DbLsn.NULL_LSN; public int preStartLNTxnCount; public int preStartLNCount; public int preStartMapLNTxnCount; public int preStartMapLNCount; public int postStartLNTxnCount; public int postStartLNCount; public int postStartMapLNTxnCount; public int postStartMapLNCount; public void increment( FileReader reader, byte currentEntryTypeNum){ if (currentEntryTypeNum == LogEntryType.LOG_CKPT_START.getTypeNum()) { startCkptLsn=reader.getLastLsn(); } else if (currentEntryTypeNum == LogEntryType.LOG_LN_TRANSACTIONAL.getTypeNum()) { if (startCkptLsn == DbLsn.NULL_LSN) { preStartLNTxnCount++; } else { postStartLNTxnCount++; } } else if (currentEntryTypeNum == LogEntryType.LOG_LN.getTypeNum()) { if (startCkptLsn == DbLsn.NULL_LSN) { preStartLNCount++; } else { postStartLNCount++; } } else if (currentEntryTypeNum == LogEntryType.LOG_MAPLN.getTypeNum()) { if (startCkptLsn == DbLsn.NULL_LSN) { preStartMapLNCount++; } else { postStartMapLNCount++; } } else if (currentEntryTypeNum == LogEntryType.LOG_MAPLN_TRANSACTIONAL.getTypeNum()) { if (startCkptLsn == DbLsn.NULL_LSN) { preStartMapLNTxnCount++; } else { postStartMapLNTxnCount++; } } } } }