List:Commits« Previous MessageNext Message »
From:ahristov Date:September 24 2007 1:10pm
Subject:PHP mysqlnd svn commit: r1058 - trunk/mysqlnd
View as plain text  
Author: ahristov
Date: 2007-09-24 15:10:13 +0200 (Mon, 24 Sep 2007)
New Revision: 1058

Modified:
   trunk/mysqlnd/mysqlnd_debug.c
   trunk/mysqlnd/mysqlnd_debug.h
   trunk/mysqlnd/mysqlnd_result.c
Log:
Add backtrace extraction. Still undecided where to dump it,
probably additional dump file, a mysqlnd setting?


Modified: trunk/mysqlnd/mysqlnd_debug.c
===================================================================
--- trunk/mysqlnd/mysqlnd_debug.c	2007-09-24 13:08:05 UTC (rev 1057)
+++ trunk/mysqlnd/mysqlnd_debug.c	2007-09-24 13:10:13 UTC (rev 1058)
@@ -27,6 +27,7 @@
 #include "mysqlnd_wireprotocol.h"
 #include "mysqlnd_palloc.h"
 #include "mysqlnd_statistics.h"
+#include "zend_builtin_functions.h"
 
 
 static const char * const mysqlnd_debug_default_trace_file = "/tmp/mysqlnd.trace";
@@ -395,7 +396,6 @@
 static void
 MYSQLND_METHOD(mysqlnd_debug, set_mode)(MYSQLND_DEBUG * self, const char * const mode)
 {
-	MYSQLND_ZTS(self);
 	size_t mode_len = strlen(mode), i;
 	enum mysqlnd_debug_parser_state state = PARSER_WAIT_MODIFIER;
 
@@ -888,6 +888,271 @@
 /* }}} */
 
 
+/* {{{ gettraceasstring() macros */
+#define TRACE_APPEND_CHR(chr)                                            \
+	*str = (char*)erealloc(*str, *len + 1 + 1);                          \
+	(*str)[(*len)++] = chr
+
+#define TRACE_APPEND_STRL(val, vallen)                                   \
+	{                                                                    \
+		int l = vallen;                                                  \
+		*str = (char*)erealloc(*str, *len + l + 1);                      \
+		memcpy((*str) + *len, val, l);                                   \
+		*len += l;                                                       \
+	}
+
+#define TRACE_APPEND_USTRL(val, vallen) \
+	{ \
+		zval tmp, copy; \
+		int use_copy; \
+		ZVAL_UNICODEL(&tmp, val, vallen, 1); \
+		zend_make_printable_zval(&tmp, &copy, &use_copy); \
+		TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
+		zval_dtor(&copy); \
+		zval_dtor(&tmp); \
+	}
+
+#define TRACE_APPEND_ZVAL(zv) \
+	if (Z_TYPE_P((zv)) == IS_UNICODE) { \
+		zval copy; \
+		int use_copy; \
+		zend_make_printable_zval((zv), &copy, &use_copy); \
+		TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
+		zval_dtor(&copy); \
+	} else { \
+		TRACE_APPEND_STRL(Z_STRVAL_P((zv)), Z_STRLEN_P((zv))); \
+	}
+
+#define TRACE_APPEND_STR(val)                                            \
+	TRACE_APPEND_STRL(val, sizeof(val)-1)
+
+#define TRACE_APPEND_KEY(key)                                            \
+	if (zend_ascii_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
+		if (Z_TYPE_PP(tmp) == IS_UNICODE) { \
+			zval copy; \
+			int use_copy; \
+			zend_make_printable_zval(*tmp, &copy, &use_copy); \
+	    TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
+	    zval_dtor(&copy); \
+		} else { \
+	    TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));           \
+	  } \
+	}
+/* }}} */
+
+
+/* {{{ mysqlnd_build_trace_args */
+static int mysqlnd_build_trace_args(zval **arg, int num_args, va_list args, zend_hash_key
*hash_key)
+{
+	char **str;
+	int *len;
+
+	str = va_arg(args, char**);
+	len = va_arg(args, int*);
+
+	/* the trivial way would be to do:
+	 * conver_to_string_ex(arg);
+	 * append it and kill the now tmp arg.
+	 * but that could cause some E_NOTICE and also damn long lines.
+	 */
+
+	switch (Z_TYPE_PP(arg)) {
+		case IS_NULL:
+			TRACE_APPEND_STR("NULL, ");
+			break;
+		case IS_STRING: {
+			int l_added;
+			TRACE_APPEND_CHR('\'');
+			if (Z_STRLEN_PP(arg) > 15) {
+				TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
+				TRACE_APPEND_STR("...', ");
+				l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
+			} else {
+				l_added = Z_STRLEN_PP(arg);
+				TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
+				TRACE_APPEND_STR("', ");
+				l_added += 3 + 1;
+			}
+			while (--l_added) {
+				if ((unsigned char)(*str)[*len - l_added] < 32) {
+					(*str)[*len - l_added] = '?';
+				}
+			}
+			break;
+		}
+		case IS_UNICODE: {
+			int l_added;
+			TSRMLS_FETCH();
+
+			/*
+			 * We do not want to apply current error mode here, since
+			 * zend_make_printable_zval() uses output encoding converter.
+			 * Temporarily set output encoding converter to escape offending
+			 * chars with \uXXXX notation.
+			 */
+			zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)),
ZEND_FROM_UNICODE, ZEND_CONV_ERROR_ESCAPE_JAVA);
+			TRACE_APPEND_CHR('\'');
+			if (Z_USTRLEN_PP(arg) > 15) {
+				TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), 15);
+				TRACE_APPEND_STR("...', ");
+				l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
+			} else {
+				l_added = Z_USTRLEN_PP(arg);
+				TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), l_added);
+				TRACE_APPEND_STR("', ");
+				l_added += 3 + 1;
+			}
+			/*
+			 * Reset output encoding converter error mode.
+			 */
+			zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)),
ZEND_FROM_UNICODE, UG(from_error_mode));
+			while (--l_added) {
+				if ((unsigned char)(*str)[*len - l_added] < 32) {
+					(*str)[*len - l_added] = '?';
+				}
+			}
+			break;
+		}
+		case IS_BOOL:
+			if (Z_LVAL_PP(arg)) {
+				TRACE_APPEND_STR("true, ");
+			} else {
+				TRACE_APPEND_STR("false, ");
+			}
+			break;
+		case IS_RESOURCE:
+			TRACE_APPEND_STR("Resource id #");
+			/* break; */
+		case IS_LONG: {
+			long lval = Z_LVAL_PP(arg);
+			char s_tmp[MAX_LENGTH_OF_LONG + 1];
+			int l_tmp = zend_sprintf(s_tmp, "%ld", lval);  /* SAFE */
+			TRACE_APPEND_STRL(s_tmp, l_tmp);
+			TRACE_APPEND_STR(", ");
+			break;
+		}
+		case IS_DOUBLE: {
+			double dval = Z_DVAL_PP(arg);
+			char *s_tmp;
+			int l_tmp;
+			TSRMLS_FETCH();
+
+			s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
+			l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval);  /* SAFE */
+			TRACE_APPEND_STRL(s_tmp, l_tmp);
+			/* %G already handles removing trailing zeros from the fractional part, yay */
+			efree(s_tmp);
+			TRACE_APPEND_STR(", ");
+			break;
+		}
+		case IS_ARRAY:
+			TRACE_APPEND_STR("Array, ");
+			break;
+		case IS_OBJECT: {
+			zstr class_name;
+			zend_uint class_name_len;
+			int dup;
+			TSRMLS_FETCH();
+
+			TRACE_APPEND_STR("Object(");
+
+			dup = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC);
+
+			if (UG(unicode)) {
+				zval tmp;
+
+				ZVAL_UNICODEL(&tmp, class_name.u, class_name_len, 1);
+				convert_to_string_with_converter(&tmp,
ZEND_U_CONVERTER(UG(output_encoding_conv)));
+				TRACE_APPEND_STRL(Z_STRVAL(tmp), Z_STRLEN(tmp));
+				zval_dtor(&tmp);
+			} else {
+				TRACE_APPEND_STRL(class_name.s, class_name_len);
+			}
+			if(!dup) {
+				efree(class_name.v);
+			}
+
+			TRACE_APPEND_STR("), ");
+			break;
+		}
+		default:
+			break;
+	}
+	return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_build_trace_string */
+static int mysqlnd_build_trace_string(zval **frame, int num_args, va_list args,
zend_hash_key *hash_key)
+{
+	char *s_tmp, **str;
+	int *len, *num;
+	long line;
+	HashTable *ht = Z_ARRVAL_PP(frame);
+	zval **file, **tmp;
+
+	str = va_arg(args, char**);
+	len = va_arg(args, int*);
+	num = va_arg(args, int*);
+
+	s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
+	sprintf(s_tmp, "#%d ", (*num)++);
+	TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
+	efree(s_tmp);
+	if (zend_ascii_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
+		if (zend_ascii_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
+			line = Z_LVAL_PP(tmp);
+		} else {
+			line = 0;
+		}
+		TRACE_APPEND_ZVAL(*file);
+		s_tmp = emalloc(MAX_LENGTH_OF_LONG + 2 + 1);
+		sprintf(s_tmp, "(%ld): ", line);
+		TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
+		efree(s_tmp);
+	} else {
+		TRACE_APPEND_STR("[internal function]: ");
+	}
+	TRACE_APPEND_KEY("class");
+	TRACE_APPEND_KEY("type");
+	TRACE_APPEND_KEY("function");
+	TRACE_APPEND_CHR('(');
+	if (zend_ascii_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
+		int last_len = *len;
+		zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp),
(apply_func_args_t)mysqlnd_build_trace_args, 2, str, len);
+		if (last_len != *len) {
+			*len -= 2; /* remove last ', ' */
+		}
+	}
+	TRACE_APPEND_STR(")\n");
+	return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+
+char * mysqlnd_get_backtrace(TSRMLS_D)
+{
+	zval *trace;
+	char *res = estrdup(""), **str = &res, *s_tmp;
+	int res_len = 0, *len = &res_len, num = 0;
+
+	MAKE_STD_ZVAL(trace);
+	zend_fetch_debug_backtrace(trace, 0, 0 TSRMLS_CC);
+
+	zend_hash_apply_with_arguments(Z_ARRVAL_P(trace),
(apply_func_args_t)mysqlnd_build_trace_string, 3, str, len, &num);
+	zval_ptr_dtor(&trace);
+
+	s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 7 + 1);
+	sprintf(s_tmp, "#%d {main}", num);
+	TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
+	efree(s_tmp);
+
+	res[res_len] = '\0';
+
+	return res;
+}
+
 /*
  * Local variables:
  * tab-width: 4

Modified: trunk/mysqlnd/mysqlnd_debug.h
===================================================================
--- trunk/mysqlnd/mysqlnd_debug.h	2007-09-24 13:08:05 UTC (rev 1057)
+++ trunk/mysqlnd/mysqlnd_debug.h	2007-09-24 13:10:13 UTC (rev 1058)
@@ -76,6 +76,8 @@
 void *	_mysqlnd_realloc(void *ptr, size_t new_size MYSQLND_MEM_D);
 void	_mysqlnd_free(void *ptr MYSQLND_MEM_D);
 
+char *	mysqlnd_get_backtrace(TSRMLS_D);
+
 #if PHP_DEBUG && !defined(PHP_WIN32)
 #define DBG_INF(msg) do { if (dbg_skip_trace == FALSE)
MYSQLND_G(dbg)->m->log(MYSQLND_G(dbg), __LINE__, __FILE__, -1, "info : ", (msg)); }
while (0)
 #define DBG_ERR(msg) do { if (dbg_skip_trace == FALSE)
MYSQLND_G(dbg)->m->log(MYSQLND_G(dbg), __LINE__, __FILE__, -1, "error: ", (msg)); }
while (0)

Modified: trunk/mysqlnd/mysqlnd_result.c
===================================================================
--- trunk/mysqlnd/mysqlnd_result.c	2007-09-24 13:08:05 UTC (rev 1057)
+++ trunk/mysqlnd/mysqlnd_result.c	2007-09-24 13:10:13 UTC (rev 1058)
@@ -324,7 +324,7 @@
 			default:{			/* Result set	*/
 				php_mysql_packet_eof fields_eof;
 				MYSQLND_RES *result;
-				uint stat = -1;
+				enum_mysqlnd_collected_stats stat = STAT_LAST;
 
 				DBG_INF("Result set pending");
 				SET_EMPTY_MESSAGE(conn->last_message, conn->last_message_len,
conn->persistent);
@@ -404,7 +404,12 @@
 					} else if (fields_eof.server_status & MYSQLND_SERVER_QUERY_NO_INDEX_USED) {
 						stat = STAT_NO_INDEX_USED;
 					}
-					if (stat != -1) {
+					if (stat != STAT_LAST) {
+						char *backtrace = mysqlnd_get_backtrace(TSRMLS_C);
+#if A0
+						php_log_err(backtrace TSRMLS_CC);
+#endif
+						efree(backtrace);
 						MYSQLND_INC_CONN_STATISTIC(&conn->stats, stat);
 					}
 				}

Thread
PHP mysqlnd svn commit: r1058 - trunk/mysqlndahristov24 Sep