/*
* Copyright (C) 2006 http://www.chaidb.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
package org.chaidb.db.index.btree;
import org.apache.log4j.Logger;
import org.chaidb.db.DbEnvironment;
import org.chaidb.db.helper.ByteTool;
import org.chaidb.db.helper.Log;
import org.chaidb.db.index.btree.bufmgr.PageNumber;
import java.io.*;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;
public class Debug extends Log {
private static final Logger logger = Logger.getLogger(Debug.class);
/**
* xzp_leon
*/
public static final boolean checkLock_DEBUG = false;
public static final boolean getXMLNodeFailed = false;
public static final boolean NULL_POINT_NO_STATIC = false;
public static final boolean DEBUG = false;
public static final boolean DEBUG_XMLNODEFAILED = false;
public static final boolean DEBUG_CHECKPAGENUMBER = false;
public static final boolean DEBUG_TRAVERAL = false;
public static final boolean DEBUG_BUFFER_SIZE = false;
public static final boolean DEBUG_PAGEINFO_TRACE = false;
public static final boolean DEBUG_BUFFEREDPAGEINFOS_REMOVE_TRACE = false;
public static final boolean DEBUG_DIRTY_TRACE = false;
public static final boolean DEBUG_DIRTY_LIST_TRACE = false;
public static final boolean DEBUG_CLEAN_LIST_TRACE = false;
public static final boolean DEBUG_CLEAN_LIST_HEADER = false;
public static final boolean DEBUG_PAGEINFO_TRACE1 = false;
public static final boolean DEBUG_ID2ROOT = false;
public static final boolean DEBUG_SHARE_MEMORY = false;
public static final boolean DEBUG_DUMP_MEMORY = false;
public static final boolean DEBUG_RESOURCE_CONTROL_BLOCK = false;
public static final boolean DEBUG_OVERFLOW_PAGE = false;
public static final boolean DEBUG_THREAD = false;
public static final boolean DEBUG_ORDER = false;
public static final boolean DEBUG_PAGE_SIZE = false;
public static final boolean DEBUG_STORAGE_FILE_SIZE = false;
public static final boolean DEBUG_PERFORMANCE = false;
public static final int _CALLER_LEVEL = 4;
/**
* class debug flag
*/
public static final boolean _DEBUG = false;
/**
* lock error
*/
public static final boolean Debug_Lock_error = false;
public static final String PAGE_DIR = "PAGE";
private static String tmpPageDir = DbEnvironment.DB_TEMP_PATH + File.separator + PAGE_DIR + File.separator;
private static StringWriter sw = new StringWriter();
private static PrintWriter pw = new PrintWriter(sw);
private static Hashtable trees = new Hashtable();
/**
* For debug usage
* flag Dump
* 1 Pagepool or buffer
* 2 Used list
* 4 Look aside list
* 8 Freeslots
* 16 FreeList
* flag can be combined value of the above value
*/
public static final byte DUMP_PAGEPOOL = 1;
public static final byte DUMP_CLEANLIST = 2;
public static final byte DUMP_DIRTYLIST = 4;
public static final byte DUMP_FREESLOTS = 8;
public static final byte DUMP_FREELIST = 16;
public static final byte DUMP_ALL = DUMP_PAGEPOOL | DUMP_CLEANLIST | DUMP_DIRTYLIST | DUMP_FREESLOTS | DUMP_FREELIST;
/**
* debug
*/
public static boolean DEBUG_DATAPAGE = false;
//private boolean DEBUG_BTREEPAGE = false;
public static boolean DEBUG_BTREEPAGE = false;
static {
Log.setThreshold(Log.LOG_DEBUG);
File f = new File(tmpPageDir);
if (!f.exists() || f.isFile()) f.mkdirs();
}
/**
* Gets Caller Stack
*
* @param level from index
* @param num the number of level we will print
*/
public static synchronized String getCallerInfo(int level, int num) {
Throwable t = new Throwable();
String s;
// Protect against multiple access to sw.
t.printStackTrace(pw);
s = sw.toString();
sw.getBuffer().setLength(0);
StringTokenizer tokens = new StringTokenizer(s, "\r\n\t");
int i = 0;
String line = null, token;
int j;
while (tokens.hasMoreTokens() && i <= level + num) {
token = tokens.nextToken();
if ((j = token.lastIndexOf("(")) == -1) {
i++;
continue;
}
token = token.substring(token.lastIndexOf(".", j));
if (i++ <= level) line = token;
else line += "\t\r\n" + token;
}
return line;
}
public static synchronized String getCallerInfo(int level) {
return getCallerInfo(level, 1);
}
private static Hashtable threads = new Hashtable();
private static Vector vPages = new Vector();
private static final int NUM_PG = 10000;
private static final int UPPER = 60 * 1024 * 1024;
private static int totalLen = 0;
/**
* Puts thread info into hashtable. Or remove it from it when the parameter is "End".
*
* @param mes The message which records the thread's message.
* @see #DEBUG_THREAD
*/
public static void recordThread(String mes) {
if (!DEBUG) return;
if (mes.equals("End")) threads.remove(Thread.currentThread().getName());
else threads.put(Thread.currentThread().getName(), mes);
}
/**
* Displays threads info. And statistics the numbers of wait and run.
*
* @return The threads info.
* @see #DEBUG_THREAD
*/
public static synchronized String displayThreads() {
short run = 0, wait = 0;
StringBuffer res = new StringBuffer(Long.toString(System.currentTimeMillis()).substring(7) + " threads status:");
Enumeration names = threads.elements();
while (names.hasMoreElements()) {
String thd = (String) names.nextElement();
if (thd.indexOf("[A]") > -1) wait++;
else run++;
res.append(thd);
}
res.append("\r\n Run=" + run + ", Wait=" + wait);
return res.toString();
}
/**
* Record special page trace info.
*
* @param pgno The page number indicated by which the page
* @param level The call stack info.
* @param mes The message.
* @see #DEBUG_PAGEINFO_TRACE
*/
public static synchronized void write(PageNumber pgno, int level, String mes) {
// if (!DEBUG) return 0;
String thread = Thread.currentThread().getName();
if (thread.length() > 6) thread = thread.substring(6);
String newMes = "\r\nT=" + Long.toString(System.currentTimeMillis()).substring(7) + " " + thread + ": " + mes + getCallerInfo(1, 15);
try {
Integer treeID = new Integer(pgno.getTreeId());
Hashtable pages = (Hashtable) trees.get(treeID);
if (pages == null) {
pages = new Hashtable();
trees.put(treeID, pages);
}
StringBuffer callerLine = (StringBuffer) pages.get(pgno);
if (callerLine == null) {
callerLine = new StringBuffer();
pages.put(pgno, callerLine);
}
totalLen += newMes.length();
callerLine.append(newMes);
if (totalLen >= UPPER) {
pageHistoryAll();
trees.clear();
logger.debug("discard " + pages.size());
}
} catch (Exception e) {
logger.error(e);
}
}
private static Vector vp_content = new Vector();
public static synchronized void dumpPage(PageNumber pn, byte[] page) {
if (!DEBUG) return;
try {
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(tmpPageDir + Integer.toHexString(pn.getPageNumber()), true)));
out.println("Dumppage: Time=" + System.currentTimeMillis() + "," + Thread.currentThread().getName());
out.println(org.chaidb.db.helper.ByteTool.toHexString(0, page, 0, page.length));
out.flush();
out.close();
} catch (Exception e) {
logger.error(e);
}
}
/**
* @param page
*/
public static synchronized void dumpPageToLog(byte[] page) {
//if (!DEBUG) return;
logger.fatal("The corrupted page is ");
StringBuffer sbuf = new StringBuffer(20000);
sbuf.append("\r\n");
int countInLine = 0;
for (int i = 0; i < page.length; i++) {
byte b = page[i];
sbuf.append(Integer.toHexString(b) + "");
countInLine++;
if (countInLine == 16) {
sbuf.append("\r\n");
countInLine = 0;
}
}
logger.fatal(sbuf.toString());
}
public static synchronized void dumpPageToFile(PageNumber pn) {
if (!DEBUG) return;
Integer key = new Integer(pn.getPageNumber());
int index = key.intValue() / NUM_PG;
Hashtable h;
//boolean found=false;
if (index >= vp_content.size()) {
h = new Hashtable();
vp_content.add(h);
} else {
h = (Hashtable) vp_content.get(index);
}
try {
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(tmpPageDir + pn.toHexString(), true)));
byte[] page = (byte[]) h.get(key);
out.println(org.chaidb.db.helper.ByteTool.toHexString(0, page, 0, page.length));
out.flush();
out.close();
} catch (Exception e) {
logger.error(e);
}
}
public static synchronized void pageHistoryAll() {
java.util.Collection colTrees = trees.values();
java.util.Iterator iterTrees = colTrees.iterator();
Hashtable hashTree = null;
java.util.Enumeration enuTree = null;
PageNumber history = null;
while (iterTrees.hasNext()) {
hashTree = (Hashtable) iterTrees.next();
enuTree = hashTree.keys();
while (enuTree.hasMoreElements()) {
history = (PageNumber) enuTree.nextElement();
pageHistory(history);
}
}
}
/**
* Print the page trace represents by page number.
*
* @param pgno The page number which
*/
public static synchronized void pageHistory(PageNumber pgno) {
// if (!DEBUG) return;
if (pgno == null) return;
PrintWriter out = null;
try {
Integer treeID = new Integer(pgno.getTreeId());
Hashtable pages = (Hashtable) trees.get(treeID);
if (pages == null) {
logger.error("Debug.pageHistory: The tree is purged");
return;
}
StringBuffer history = (StringBuffer) pages.get(pgno);
String file = tmpPageDir + (pgno.toHexString().replace(',', '-'));
out = new PrintWriter(new BufferedWriter(new FileWriter(file, true)));
out.println(history.toString());
} catch (Exception e) {
logger.error(e);
} finally {
if (out != null) out.close();
}
}
/**
* Dumps the thread info indicated by the parameter to tmpPageDir.
*
* @param thd The thread name.
* @see #DEBUG_THREAD
*/
public static synchronized void dumpThread(String thd) {
PrintWriter out = null;
try {
out = new PrintWriter(new BufferedWriter(new FileWriter(tmpPageDir + thd, true)));
String line = (threads.get(thd)).toString();
out.println(line);
out.flush();
} catch (Exception e) {
logger.error(e);
} finally {
if (out != null) {
out.close();
}
}
}
public static synchronized String getDebugInfo() {
return ("[debug] Time=" + System.currentTimeMillis() + " " + Thread.currentThread().getName() + ": ");
}
public static synchronized void main(String args[]) {
String s = Debug.getCallerInfo(1);
logger.debug("s is " + s + ".");
}
private static Hashtable pages = new Hashtable();
public static synchronized void logPage(String pg, int ref, String mes) {
if (!DEBUG) return;
if (ref == 0) pages.remove(pg);
else {
StringBuffer callerLine = (StringBuffer) pages.get(pg);
if (callerLine == null) callerLine = new StringBuffer();
callerLine.append("\r\n\t");
callerLine.append("Time=" + System.currentTimeMillis() + " " + Thread.currentThread().getName() + ": " + mes + " fix=" + ref + " " + getCallerInfo(4, 3));
pages.put(pg, callerLine);
}
}
public static synchronized void pagesToFile(String name) {
try {
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(tmpPageDir + name, true)));
Enumeration keys = pages.keys();
while (keys.hasMoreElements()) {
String line = (String) keys.nextElement();
line += "\t" + (pages.get(line)).toString();
out.println(line);
out.println();
}
out.flush();
out.close();
} catch (Exception e) {
logger.error(e);
}
}
static boolean p_done = false;
public static synchronized void flushPages() {
if (!DEBUG || p_done) return;
PrintWriter out = null;
try {
logger.debug("vPage size=" + vPages.size());
for (int i = 0; i < vPages.size(); i++) {
Hashtable h = (Hashtable) vPages.get(i);
Enumeration pages = h.keys();
logger.debug("Flushing vPage[" + i + "]");
//int count=0;
while (pages.hasMoreElements()) {
Integer key = (Integer) pages.nextElement();
String line = (h.get(key)).toString();
out = new PrintWriter(new BufferedWriter(new FileWriter(tmpPageDir + Integer.toHexString(key.intValue()), true)));
out.println(line);
out.flush();
out.close();
}
}
p_done = true;
} catch (Exception e) {
logger.error(e);
} finally {
if (out != null) out.close();
}
}
/**
* Check whether the page number of acquired page equals the original page number.
*
* @param pn The original page number
* @param page The raw page
* @return True if equals, otherwise false.
*/
public static boolean checkPageNumber(PageNumber pn, byte[] page) {
if (pn.getPageNumber() == 0) { //o page is right
return true;
}
int i = ByteTool.bytesToInt(page, 0, true);
if (pn.getPageNumber() != i) {
logger.debug("The original page number is: " + pn.toHexString());
logger.debug("The translated page number is: " + i);
}
return (pn.getPageNumber() == i);
}
/**
* Flush Threads info to tmpPageDir.
*
* @see #DEBUG_THREAD
*/
public static synchronized void flushThreads() {
PrintWriter out = null;
try {
logger.fatal("Flushing threads");
Enumeration names = threads.keys();
while (names.hasMoreElements()) {
String key = (String) names.nextElement();
String line = (threads.get(key)).toString();
out = new PrintWriter(new BufferedWriter(new FileWriter(tmpPageDir + key, true)));
out.println(line);
out.flush();
}
} catch (Exception e) {
logger.error(e);
} finally {
if (out != null) out.close();
}
}
public static long flushTimes = 0;
public static long flushTime = 0;
public static long getPageTime = 0;
public static long getTotalPageTime = 0;
private static long hitCount = 0;
private static long bufferHitCount = 0;
public static long blockOnWrite = 0;
public static long blockOnFlush = 0;
public static long blockOnRealFlush = 0;
public synchronized static void increaseHitCount() {
hitCount++;
}
public synchronized static void increaseBufferHitCount() {
bufferHitCount++;
}
public static synchronized void writePerformanceData() {
logger.error("The flush times is " + flushTimes);
logger.error("The flush time is " + flushTime);
logger.error("The get page time is " + getPageTime);
logger.error("The get total page time is " + getTotalPageTime);
logger.error("The hit count is " + hitCount);
logger.error("The buffer hit count is " + bufferHitCount);
logger.error("The block on write count is " + blockOnWrite);
logger.error("The block on flush count is " + blockOnFlush);
logger.error("The block on real flush count is " + blockOnRealFlush);
flushTimes = 0;
flushTime = 0;
getPageTime = 0;
getTotalPageTime = 0;
hitCount = 0;
bufferHitCount = 0;
blockOnWrite = 0;
blockOnFlush = 0;
blockOnRealFlush = 0;
}
}