|
標簽:proxool
瀏覽(678) 日期:2008-03-19
我终于找到了出问题的线程了。 通过thread dump 我发现如下线程一直在运行: "resin-tcp-connection-*:80-6075" daemon prio=1 tid=0x0857aac8 nid=0x7fb0 runnable [0x82dfe000..0x82dff19c] at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116) at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:103) at org.logicalcobwebs.proxool.AbstractProxyStatement.testException(AbstractProxyStatement.java:65) at org.logicalcobwebs.proxool.ProxyStatement.invoke(ProxyStatement.java:146) at org.logicalcobwebs.proxool.ProxyStatement.intercept(ProxyStatement.java:57) at $java.sql.Statement$$EnhancerByCGLIB$$1a91e2dc.close() at com.tag.db.doEndTag(valuetag.java:438) at _jsp._rst._eng_0aa__jsp._jspService(_products_0viewinfo__jsp.java:75) at com.caucho.jsp.JavaPage.service(JavaPage.java:60) at com.caucho.jsp.Page.pageservice(Page.java:570) at com.caucho.server.dispatch.PageFilterChain.doFilter(PageFilterChain.java:159) at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152) at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70) at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152) at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70) at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:178) at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:229) at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:267) at com.caucho.server.port.TcpConnection.run(TcpConnection.java:388) - locked <0x5c472008> (a java.lang.Object) at com.caucho.util.ThreadPool.runTasks(ThreadPool.java:490) at com.caucho.util.ThreadPool.run(ThreadPool.java:423) at java.lang.Thread.run(Thread.java:595) 然后我又查看了顶级的代码调用 at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116) 也就是testException这个方法一直在执行,我不清楚为什么为会出现如此死循环。 我想问问大家,什么样的代码会导致proxool的testException一直运行着。 --------------------------------------------------------------------------------
不知道是分数不够,还是人才稀少,怎么就没人回答呢。郁闷 -------------------------------------------------------------------------------- 为什么会重复出现: at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152) at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70) at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152) at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70) 谁能告诉我啊。 -------------------------------------------------------------------------------- 本来proxool是很有口碑的连接池 ,怎么会导致 at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116)中testException运行没完没了呢。 -------------------------------------------------------------------------------- 努力接分升级中...帮你up! -------------------------------------------------------------------------------- filter 死循环调用? -------------------------------------------------------------------------------- 回复:iihero(阿黑哥) 应该不是filter的引起的,如果是filter的话,那所有的页面都会很容易进入死循环。 -------------------------------------------------------------------------------- 下面就是这个永远不结束的方法,我看了一下源代码,虽然有循环部分,但也不导致死循环, 大伙帮我分析一下,具体是什么原因会导致下面的代码一直执行? /** * Test to see if an exception is a fatal one * @param cpd the definition so we can find out what a fatal exception looks like * @param t the exception to test * @param level the recursion level (max 20) * @return true if it is fatal */ protected static boolean testException(ConnectionPoolDefinitionIF cpd, Throwable t, int level) { boolean fatalSqlExceptionDetected = false; Iterator i = cpd.getFatalSqlExceptions().iterator(); while (i.hasNext()) { if (t.getMessage() != null && t.getMessage().indexOf((String) i.next()) > -1) { // This SQL exception indicates a fatal problem with this connection. fatalSqlExceptionDetected = true; } } // If it isn`t fatal, then try testing the contained exception if (!fatalSqlExceptionDetected && level < 20) { Throwable cause = getCause(t); if (cause != null) { fatalSqlExceptionDetected = testException(cpd, cause, level + 1); } } return fatalSqlExceptionDetected; } -------------------------------------------------------------------------------- while (i.hasNext()) { if (t.getMessage() != null && t.getMessage().indexOf((String) i.next()) > -1) { // This SQL exception indicates a fatal problem with this connection. fatalSqlExceptionDetected = true; } } t.getMessage() != null这句话不成立的话,就没机会调用i.next() 就死循环了。 -------------------------------------------------------------------------------- 在网上大家都对proxool赞赏有加,但是我们的项目出现如此严重的错误,实属不应该, 请兄弟们帮我查明此原因,不让我再去怀疑proxool的过错了,把清白留proxool。 -------------------------------------------------------------------------------- 回复:zhmt(不爽你就用分砸我!!!) t.getMessage() != null不成立,也应该会再次调用i.hasNext()吧 -------------------------------------------------------------------------------- 请大伙帮我把铁顶起来,都快两天了,还是没找到答案。 -------------------------------------------------------------------------------- 你说的错了,&& 运算是从左到右,左边的不成立,直接就返回false了,不再计算右边的。所以不调用i.next()。 楼主要加强基础。 -------------------------------------------------------------------------------- 你可以写个小例子测试一下。 -------------------------------------------------------------------------------- 当 t.getMessage() != null不成立时,是“t.getMessage().indexOf((String) i.next()) > -1”没机会执行。不是i.hasNext -------------------------------------------------------------------------------- 回复: zhmt(不爽你就用分砸我!!!) 我还是不明白,t.getMessage() != null这句话不成立的话,就会导致死循环。 -------------------------------------------------------------------------------- 就算“t.getMessage().indexOf((String) i.next()) > -1不知道,也不会导致死循环啊。 -------------------------------------------------------------------------------- 我上面的那段代码是从proxool中取出来的,如果这么容易就死循环了,那我就要怀疑这个东西的安全性啦。 -------------------------------------------------------------------------------- 你的问题的背景是什么啊? 不能光看这一点。 -------------------------------------------------------------------------------- resin-tcp-connection-*:80-6075" daemon prio=1 tid=0x0857aac8 nid=0x7fb0 runnable 这是个守护线程,(daemon),一直运行的话,是很正常的。可能问题不在这里,你的是什么性能问题啊? -------------------------------------------------------------------------------- 好,那我就说说背景 : 我维护的是个网站项目,网站经常服务器cpu 99%,并且上去了就不下来了,开始我就确定是 死循环的问题,但是找不到根据,前两天我用kill -3 pid,每隔5分钟Thread Dump一下,发现 上面的线程一直在虚拟机(JVM)里面运行者。那只有死循环才不会退出的。 我不知道我讲清楚没? -------------------------------------------------------------------------------- daemon是守护进程,但是不应该不结束。 -------------------------------------------------------------------------------- 你确信是这个线程启动后cpu才到100%的吗? -------------------------------------------------------------------------------- 是的。在平时,我找不到这样的线程。 -------------------------------------------------------------------------------- 我查了一下它的源码,这个类是用来检查一个异常是否是严重异常,它能一直运行说明你的应用导致了很多sql异常。如果这个pool是经过大家的检验的话,可能你的应用中,哪一部分的sql调用很有问题。 -------------------------------------------------------------------------------- 是的,但是很多异常也会有个数量限制啊,可能处理校验的速度慢啊,而不会出现,死循环啊。 在页面上传入的sql语句难免有些问题,我测试过,一般情况下,系统会自动处理的,但是我想在就不明白,什么情况下,什么样的SQL语句会导致死循环。 -------------------------------------------------------------------------------- 你看了有多少个这样线程了吗? 可能不是死循环,而是线程结束后又被启动起来。或者是启动了多个这样的线程。 如果不是我感才说的那个死循环的,就不可能出现死循环了(next和hasNext要成对使用才不会死在那,如果只使用hasNext而不使用next,那么iterator是不往下走的,就会死了。)。 另外它的递归调用也不会超过20层,所以也不会死。 -------------------------------------------------------------------------------- 我觉得从自己的应用上来改进应该更好。 -------------------------------------------------------------------------------- 回复:zhmt(不爽你就用分砸我!!!) 你说的有道理,如果 t.getMessage() ==null的话,就会陷入死循环。 但是我看我们的代码都是按照JDBC规范来写的啊。 下面我贴些原码,帮我看看有什么问题。 -------------------------------------------------------------------------------- public HashMap getdbValue(PoolBean pool) throws Exception { if(pool.getLog().isDebugEnabled()) pool.getLog().debug("star getdbValue"); String system_name = pool.getDatabaseInfo().getSystemName(); HashMap result = null; String temp_sql = createSql(); if(temp_sql == null) throw new SQLException("not sql statement"); Statement stmt = null; ResultSet rs = null; Connection con = null; try { con = pool.getNoInfoConnection();// .getConnection(); con.setReadOnly(true); stmt = con.createStatement(); rs = stmt.executeQuery(temp_sql); // rs = stmt.executeQuery(sql); if (rs != null) { ResultSetMetaData rsmd = rs.getMetaData(); int colCount = rsmd.getColumnCount(); if (rs.next()) { result = new HashMap(); for (int i = 1; i <= colCount; i++) { String name = rsmd.getColumnName(i); name = name.toLowerCase(); String type_name = rsmd.getColumnTypeName(i).toLowerCase(); // System.out.println("field name : " + name + " , type_anme : " + type_name); if ("text".equals(type_name)) { //当字段类型为text时,如果直接用rs.getObject(i)取数据,在jtds1.0版本中不能直接取出,改为以下方式即可 2005-07-22 张贵平 String tt_str = rs.getString(i); // System.out.println("text -- "+tt_str); if (tt_str == null) tt_str = ""; else tt_str = tt_str.trim(); result.put(name.trim(), tt_str); } else { Object obj_value = rs.getObject(i); if (obj_value instanceof java.lang.String) { String t_str = null; if (obj_value == null) t_str = ""; else t_str = String.valueOf(obj_value).trim(); result.put(name.trim(), t_str); } else { result.put(name.trim(), obj_value); } } } } rsmd = null; } rs.close(); stmt.close(); con.setReadOnly(false); con.close(); } catch(SQLException e) { //CloseCon.Close(con); pool.getLog().error(system_name+","+e.getMessage()+",sql:"+temp_sql); throw new SQLException("database perform error : " + e.getMessage()); } finally { CloseCon.Close(con); } return result; } 从线程堆栈上看$java.sql.Statement$$EnhancerByCGLIB$$1a91e2dc.close() ,是从stmt.close()进去的。 --------------------------------------------------------------------------------
觉得不规范 rs.close(); stmt.close(); con.setReadOnly(false); con.close(); 以上这些东西都要放在finnally块中的。 我没用过PoolBean,不知道怎么用,觉得数据库的操作好像没多大问题。你倒网上搜索资料看看吧。 -------------------------------------------------------------------------------- 你看下Filter里面的跳转是不是错了。 -------------------------------------------------------------------------------- 回复:zhmt(不爽你就用分砸我!!!) PoolBean 是我们自己写的一个类,主要是做跟连接池的衔接工作。 是的,不是很规范,但是这样也应该不会导致proxool死循环。 -------------------------------------------------------------------------------- 我们自己的Filter类,看看有什么问题。 public class SetCharacterEncodingFilter implements Filter { Log log = LogFactory.getLog(this.getClass().getName()); // ----------------------------------------------------- Instance Variables /** * The default character encoding to set for requests that pass through * this filter. */ protected String encoding = null; /** * The filter configuration object we are associated with. If this value * is null, this filter instance is not currently configured. */ protected FilterConfig filterConfig = null;
/** * 上传文件的最大大小 */ protected int fileMaxLength = 200*1024; //200K /** * Should a character encoding specified by the client be ignored? */ protected boolean ignore = true; /** * Take this filter out of service. */ public void destroy() {
this.encoding = null; this.filterConfig = null; } /** * Select and set (if specified) the character encoding to be used to * interpret request parameters for this request. * * @param request The servlet request we are processing * @param result The servlet response we are creating * @param chain The filter chain we are processing * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// Conditionally select and set the character encoding to be used HttpServletRequest t_re = (HttpServletRequest) request; String re_uri = trimString(t_re.getRequestURI()); String re_host = trimString(t_re.getServerName()); String qu_str = trimString(t_re.getQueryString()); if (re_uri.indexOf(".do") > 0) { if (log.isInfoEnabled()) log.info(re_host + re_uri + "?" + qu_str);
try { if (ignore || (request.getCharacterEncoding() == null)) { String encoding = selectEncoding(request); if (encoding != null) request.setCharacterEncoding(encoding); } // Pass control on to the next filter chain.doFilter(request, response); } catch(Exception e) { // e.printStackTrace(); String error_mes = e.getMessage(); String strServerName = null; String strQueryString = null; String requestUrl = null; String remoteAddr = null; String referer = ""; if(error_mes.indexOf("reset")<0 ) { try { strServerName = t_re.getServerName(); strQueryString = t_re.getQueryString(); requestUrl = t_re.getRequestURI(); // strQueryString = CodeTransfer.ISOToUnicode(strQueryString); referer = t_re.getHeader("referer"); remoteAddr = t_re.getRemoteAddr(); } catch (Exception e1) {} if (error_mes != null && !"null".equals(error_mes)&& error_mes.length() > 0) { log.error(",exception:" + error_mes + strServerName + " , " + strQueryString + " , " + requestUrl + " , " + referer); // System.out.println("exception at filter:" + // error_mes); } } if(log.isInfoEnabled()) log.info(strServerName + " , " + strQueryString+ " , " + requestUrl + " , " + referer); } } /** * Place this filter into service. * * @param filterConfig The filter configuration object */ public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig; this.encoding = filterConfig.getInitParameter("encoding"); String value = filterConfig.getInitParameter("ignore"); String file_max_length = filterConfig.getInitParameter("file_max_length"); if(file_max_length!=null && file_max_length.length() >0) { fileMaxLength = com.kenfor.util.MyUtil.getStringToInt(file_max_length,200)*1024; } if (value == null) this.ignore = true; else if (value.equalsIgnoreCase("true")) this.ignore = true; else if (value.equalsIgnoreCase("yes")) this.ignore = true; else this.ignore = false; } /** * Select an appropriate character encoding to be used, based on the * characteristics of the current request and/or filter initialization * parameters. If no character encoding should be set, return * null. * * The default implementation unconditionally returns the value configured * by the encoding initialization parameter for this * filter. * * @param request The servlet request we are processing */ protected String selectEncoding(ServletRequest request) { return (this.encoding); } private String trimString(String value) { String result = ""; if(value !=null) result = value.trim(); return result; } }
-------------------------------------------------------------------------------- 如果真的是proxool,那我应该感到欣慰,如果是我们写的代码不当引起的,但我就真的无地之容了。 -------------------------------------------------------------------------------- 呵呵,这个我也搞不清楚,楼主最好把你们的那个poolBean自己测试一下。 能找到那种情况下出那个错误是最好的。 看看循环使用的时候是否也抛出这个异常,如果这样的话就查查哪的问题吧。如果不出错,可能就是sql写的有问题了。
|