Monday, November 2, 2009

PHP and SAX




I l@ve RuBoard










PHP and SAX


PHP 4.0 comes with a very capable SAX parser based on the expat library. Created by James Clark, the expat library is a fast, robust SAX implementation that provides XML parsing capabilities to a number of open-source projects, including the Mozilla browser (http://www.mozilla.org/).


If you're using a stock PHP binary, it's quite likely that you'll need to recompile PHP to add support for this library to your PHP build. Detailed instructions for accomplishing this are available in Appendix A, "Recompiling PHP to Add XML Support."



A Simple Example


You can do a number of complex things with a SAX parser; however, I'll begin with something simple to illustrate just how it all fits together. Let's go back to the previous XML document (see Listing 2.1), and write some PHP code to process this document and do something with the data inside it (see Listing 2.2).



Listing 2.2 Generic PHP-Based XML Parser


<html>
<head>
<basefont face="Arial">
</head>
<body>

<?php
// XML data file
$xml_file = "fox.xml";

// initialize parser
$xml_parser = xml_parser_create();

// set callback functions
xml_set_element_handler($xml_parser, "startElementHandler", "endElementHandler");
xml_set_character_data_handler($xml_parser, "characterDataHandler");

// read XML file
if (!($fp = fopen($xml_file, "r")))
{
die("File I/O error: $xml_file");
}
// parse XML
while ($data = fread($fp, 4096))
{
// error handler
if (!xml_parse($xml_parser, $data, feof($fp)))
{
die("XML parser error: " .
xml_error_string(xml_get_error_code($xml_parser)));
}
}

// all done, clean up!
xml_parser_free($xml_parser);
?>
</body>
</html>

I'll explain Listing 2.2 in detail:



  1. The first order of business is to initialize the SAX parser. This is accomplished via PHP's aptly named xml_parser_create() function, which returns a handle for use in successive operations involving the parser.


    $xml_parser = xml_parser_create();

  2. With the parser created, it's time to let it know which events you would like it to monitor, and which user-defined functions (or callback functions) it should call when these events occur. For the moment, I'm going to restrict my activities to monitoring start tags, end tags, and the data embedded within them:


    xml_set_element_handler($xml_parser, "startElementHandler", "endElementHandler");
    xml_set_character_data_handler($xml_parser, "characterDataHandler");


    Speaking Different Tongues


    It's possible to initialize the parser with a specific encoding. For example:



    $xml_parser = xml_parser_create("UTF-8");

    PHP's SAX parser currently supports the following encodings:



    • ISO-8859-1


    • US-ASCII


    • UTF-8



    An attempt to use an unsupported encoding will result in a slew of ugly error messages. Try it yourself to see what I mean.



    What have I done here? Very simple. I've told the parser to call the function startElementHandler() when it finds an opening tag, the function endElementHandler() when it finds a closing tag, and the function characterDataHandler() whenever it encounters character data within the document.


    When the parser calls these functions, it will automatically pass them all relevant information as function arguments. Depending on the type of callback registered, this information could include the element name, element attributes, character data, processing instructions, or notation identifiers.


    From Listing 2.2, you can see that I haven't defined these functions yet; I'll do that a little later, and you'll see how this works in practice. Until these functions have been defined, any attempt to run the code from Listing 2.2 as it is right now will fail.


  3. Now that the callback functions have been registered, all that remains is to actually parse the XML document. This is a simple exercise. First, create a file handle for the document:


    if (!($fp = fopen($xml_file, "r")))
    {
    die("File I/O error: $xml_file");
    }

    Then, read in chunks of data with fread(), and parse each chunk using the xml_parse() function:



    while ($data = fread($fp, 4096))
    {
    // error handler
    if (!xml_parse($xml_parser, $data, feof($fp)))
    {
    die("XML parser error: " .
    xml_error_string(xml_get_error_code($xml_parser)));
    }
    }

    In the event that errors are encountered while parsing the document, the script will automatically terminate via PHP's die() function. Detailed error information can be obtained via the xml_error_string() and xml_get_error_code() functions (for more information on how these work, see the "Handling Errors" section).


  4. After the complete file has been processed, it's good programming practice to clean up after yourself by destroying the XML parser you created:


    xml_parser_free($xml_parser);

    That said, in the event that you forget, PHP will automatically destroy the parser for you when the script ends.




Endgame


You already know that SAX can process XML data in chunks, making it possible to parse XML documents larger than available memory. Ever wondered how it knows when to stop?


That's where the optional third parameter to xml_parse() comes in. As each chunk of data is read from the XML file, it is passed to the xml_parse() function for processing. When the end of the file is reached, the feof() function returns true, which tells the parser to stop and take a well-deserved break.



The preceding four steps make up a pretty standard process, and you'll find yourself using them over and over again when processing XML data with PHP's SAX parser. For this reason, you might find it more convenient to package them as a separate function, and call this function wherever required�a technique demonstrated in Listing 2.23.


With the generic XML processing code out of the way, let's move on to the callback functions defined near the top of the script.You'll remember that I registered the following three functions:




  • startElementHandler()
    Executed when an opening tag is encountered




  • endElementHandler()
    Executed when a closing tag is encountered




  • characterDataHandler()
    Executed when character data is encountered




Listing 2.3 is the revised script with these handlers included.



Listing 2.3 Defining SAX Callback Functions


<html>
<head>
<basefont face="Arial">
</head>
<body>
<?php

// run when start tag is found
function startElementHandler($parser, $name, $attributes)
{
echo "Found opening tag of element: <b>$name</b> <br>";

// process attributes
while (list ($key, $value) = each ($attributes))
{
echo "Found attribute: <b>$key = $value</b> <br>";
}
}

// run when end tag is found
function endElementHandler($parser, $name)
{
echo "Found closing tag of element: <b>$name</b> <br>";
}
// run when cdata is found
function characterDataHandler($parser, $cdata)
{
echo "Found CDATA: <i>$cdata</i> <br>";
}

// XML data file
$xml_file = "fox.xml";

// initialize parser
$xml_parser = xml_parser_create();

// set callback functions
xml_set_element_handler($xml_parser, "startElementHandler", "endElementHandler");
xml_set_character_data_handler($xml_parser, "characterDataHandler");

// read XML file
if (!($fp = fopen($xml_file, "r")))
{
die("File I/O error: $xml_file");
}

// parse XML
while ($data = fread($fp, 4096))
{
// error handler
if (!xml_parse($xml_parser, $data, feof($fp)))
{
die("XML parser error: " .
xml_error_string(xml_get_error_code($xml_parser)));
}
}

// all done, clean up!
xml_parser_free($xml_parser);

?>
</body>
</html>

Nothing too complex here. The tag handlers print the names of the tags they encounter, whereas the character data handler prints the data enclosed within the tags. Notice that the startElementHandler() function automatically receives the tag name and attributes as function arguments, whereas the characterDataHandler() gets the CDATA text.


And when you execute the script through a browser, here's what the end product looks like (and if you're wondering why all the element names are in uppercase, take a look at the "Controlling Parser Behavior" section):



Found opening tag of element: SENTENCE
Found CDATA: The
Found opening tag of element: ANIMAL
Found attribute: COLOR = blue
Found CDATA: fox
Found closing tag of element: ANIMAL
Found CDATA: leaped over the
Found opening tag of element: VEGETABLE
Found attribute: COLOR = green
Found CDATA: cabbage
Found closing tag of element: VEGETABLE
Found CDATA: patch and vanished into the darkness.
Found closing tag of element: SENTENCE

Not all that impressive, certainly�but then again, we're just getting started!







    I l@ve RuBoard



    8.6. C/C++ Development











     < Day Day Up > 







    8.6. C/C++ Development



    Java isn't the only language that the Eclipse IDE supports. The C/C++ Development Toolkit (CDT) comes with everything you need for C/C++ development except the tool chain itself (i.e., the compiler, linker, and debugger). CDT works with a variety of tools from various embedded systems vendors; for ordinary desktop applications, you can download and use the free gcc compiler and gdb debugger from the GNU project.






    Web sites





    http://www.eclipse.org/cdt



    http://www.gnu.org



















       < Day Day Up > 



      3.1 Introduction




      I l@ve RuBoard










      3.1 Introduction



      This chapter focuses on the
      SELECT statement that is used for retrieving
      information from a database. It provides some essential background
      that shows various ways you can use SELECT to tell
      MySQL what you want to see. You should find the chapter helpful if
      your SQL background is limited or if you want to find out about the
      MySQL-specific extensions to SELECT syntax.
      However, there are so many ways to write SELECT
      queries that we'll necessarily touch on just a few.
      You may wish to consult the MySQL Reference Manual or a MySQL text
      for more information about the syntax of SELECT,
      as well as the functions and operators that you can use for
      extracting and manipulating data.



      SELECT gives
      you control over several aspects of record retrieval:




      • Which table to use


      • Which columns to display from the table


      • What names to give the columns


      • Which rows to retrieve from the table


      • How to sort the rows



      Many useful queries are quite simple and don't
      specify all those things. For example, some forms of
      SELECT don't even name a
      table�a fact used in Recipe 1.32, which
      discusses how to use mysql as a calculator. Other
      non-table-based queries are useful for purposes such as checking what
      version of the server you're running or the name of
      the current database:



      mysql> SELECT VERSION( ), DATABASE( );
      +-------------+------------+
      | VERSION( ) | DATABASE( ) |
      +-------------+------------+
      | 3.23.51-log | cookbook |
      +-------------+------------+


      However, to answer more involved questions, normally
      you'll need to pull information from one or more
      tables. Many of the examples in this chapter use a table named
      mail, which contains columns used to maintain a
      log of mail message traffic between users on a set of hosts. Its
      definition looks like this:



      CREATE TABLE mail
      (
      t DATETIME, # when message was sent
      srcuser CHAR(8), # sender (source user and host)
      srchost CHAR(20),
      dstuser CHAR(8), # recipient (destination user and host)
      dsthost CHAR(20),
      size BIGINT, # message size in bytes
      INDEX (t)
      );


      And its contents look like this:



      +---------------------+---------+---------+---------+---------+---------+
      | t | srcuser | srchost | dstuser | dsthost | size |
      +---------------------+---------+---------+---------+---------+---------+
      | 2001-05-11 10:15:08 | barb | saturn | tricia | mars | 58274 |
      | 2001-05-12 12:48:13 | tricia | mars | gene | venus | 194925 |
      | 2001-05-12 15:02:49 | phil | mars | phil | saturn | 1048 |
      | 2001-05-13 13:59:18 | barb | saturn | tricia | venus | 271 |
      | 2001-05-14 09:31:37 | gene | venus | barb | mars | 2291 |
      | 2001-05-14 11:52:17 | phil | mars | tricia | saturn | 5781 |
      | 2001-05-14 14:42:21 | barb | venus | barb | venus | 98151 |
      | 2001-05-14 17:03:01 | tricia | saturn | phil | venus | 2394482 |
      | 2001-05-15 07:17:48 | gene | mars | gene | saturn | 3824 |
      | 2001-05-15 08:50:57 | phil | venus | phil | venus | 978 |
      | 2001-05-15 10:25:52 | gene | mars | tricia | saturn | 998532 |
      | 2001-05-15 17:35:31 | gene | saturn | gene | mars | 3856 |
      | 2001-05-16 09:00:28 | gene | venus | barb | mars | 613 |
      | 2001-05-16 23:04:19 | phil | venus | barb | venus | 10294 |
      | 2001-05-17 12:49:23 | phil | mars | tricia | saturn | 873 |
      | 2001-05-19 22:21:51 | gene | saturn | gene | venus | 23992 |
      +---------------------+---------+---------+---------+---------+---------+


      To create the mail table and load its contents,
      change location into the tables directory of the
      recipes distribution and run this command:



      % mysql cookbook < mail.sql


      This chapter also uses other tables from time to time. Some of these
      were used in previous chapters, while others are new. For any that
      you need to create, do so the same way as for the
      mail table, using scripts in the
      tables directory. In addition, the text for many
      of the scripts and programs used in the chapter may be found in the
      select directory. You can use the files there to
      try out the examples more easily.



      Many of the queries shown here can be tried out with
      mysql, which you can read about in Chapter 1. Some of the examples issue queries from
      within the context of a programming language. See Chapter 2 for background on programming techniques.









        I l@ve RuBoard



        Chapter 30



        [ Team LiB ]






        Chapter 30


        30.1


        30.1

        The parent keeps the listening socket open in case it needs to fork additional children at some later time (which would be an enhancement to our code).

        30.2

        Yes, a datagram socket can be used to pass a descriptor instead of using a stream socket. With a datagram socket, the parent does not receive an EOF on its end of the stream pipe when a child terminates prematurely, but the parent could use SIGCHLD for this purpose. One difference in this scenario, where SIGCHLD can be used versus our icmpd daemon in Section 28.7, is that in the latter, there was no parent/child relationship between the client and server so the EOF on the stream pipe was the only way for the server to detect the disappearance of a client.








          [ Team LiB ]



          16.1 Interpreting mysqld Server Information











           < Day Day Up > 





          16.1 Interpreting mysqld Server Information



          The main purpose of the MySQL server is to perform queries on behalf of clients that need access to databases. However, the server also keeps track of information that is useful to administrators, and you can ask the server to report this information by using various forms of the SHOW statement:



          • SHOW VARIABLES displays server system variables. These indicate such things as directory locations, server capabilities, and sizes of caches and buffers. You can set system variables to control how the server operates. They can be set at server startup time, and many of them can be changed while the server is running. Also, the built-in value for many system variables can be specified at compile time if you build MySQL from source.

          • SHOW STATUS displays server status variables that indicate the extent and types of activities the server is performing. These variables provide information such as how long the server has been running, number of queries processed, amount of network traffic, and statistics about the query cache. You can use status information to assess how much of a load your server is processing and how well it is handling the load. This information provides useful feedback for assessing whether system variables should be changed to improve server performance.



          This chapter discusses several representative system and status variables, but many more exist. The MySQL Reference Manual provides a full list of variable names and meanings.



          16.1.1 Accessing Server Configuration Information



          Many aspects of server operation are controlled by means of a set of system variables that reflect server configuration. To display these variables, use the SHOW VARIABLES statement:










          mysql> SHOW VARIABLES;

          +-------------------------+-------------------+

          | Variable_name | Value |

          +-------------------------+-------------------+

          | back_log | 50 |

          | basedir | /usr/local/mysql/ |

          | binlog_cache_size | 32768 |

          | bulk_insert_buffer_size | 8388608 |

          | character_set | latin1 |

          ...




          To display only those variables with names that match a given pattern, add a LIKE pattern-matching clause. The pattern is not case sensitive and may contain the % and _ wildcard pattern metacharacters. For example, the sizes for many of the server's buffers can be displayed as follows:










          mysql> SHOW VARIABLES LIKE '%buffer_size';

          +-------------------------+---------+

          | Variable_name | Value |

          +-------------------------+---------+

          | bulk_insert_buffer_size | 8388608 |

          | innodb_log_buffer_size | 1048576 |

          | join_buffer_size | 131072 |

          | key_buffer_size | 8388600 |

          | myisam_sort_buffer_size | 8388608 |

          | read_buffer_size | 131072 |

          | read_rnd_buffer_size | 262144 |

          | sort_buffer_size | 2097144 |

          +-------------------------+---------+




          If the pattern contains no metacharacters, the statement displays only the named variable:










          mysql> SHOW VARIABLES LIKE 'datadir';

          +---------------+------------------------+

          | Variable_name | Value |

          +---------------+------------------------+

          | datadir | /usr/local/mysql/data/ |

          +---------------+------------------------+




          System variables can be displayed in other ways as well. mysqladmin variables provides command-line access to the complete list of system variables. The MySQLCC graphical client provides access to them in its server administration window. Both clients implement this capability by sending a SHOW VARIABLES statement to the server and displaying the results.



          System variables can be set at server startup time using options on the command line or in option files. For example, on a Unix machine, you can put the following lines in the /etc/my.cnf option file to specify a data directory of /var/mysql/data and a key buffer size of 16MB:










          [mysqld]

          datadir = /var/mysql/data

          key_buffer_size = 16M




          Numeric option values can have a suffix letter of K, M, or G to indicate units of kilobytes, megabytes, or gigabytes, respectively.



          Some server system variables are static and can only be set at startup time. (You need not know which for the exam.) For example, you can specify the data directory by means of a datadir startup option, but you cannot tell a server that's running to use a different data directory. Other variables are dynamic and can be changed while the server is running. For example, either of the following statements tells the server to change the size of the key buffer to 24MB:










          mysql> SET GLOBAL key_buffer_size = 24*1024*1024;

          mysql> SET @@global.key_buffer_size = 24*1024*1024;




          With a SET statement, you cannot use a suffix of K, M, or G to indicate units for the value, but you can use an expression.



          The key_buffer_size variable is (as the preceding statements indicate) a global server variable. Some variables exist in both global and session forms:



          • The global form applies server-wide and is used to initialize the corresponding session variable for new client connections. Each client may subsequently change its own session variable value.

          • The session form is session-specific and applies only to a particular client connection.



          To set a global variable, you must have the SUPER privilege. Any client may set its own session variables.



          An example of the type of variable that has both forms is table_type, which controls the default table type used for CREATE TABLE statements that do not specify a table type explicitly. The global table_type value is used to set the session table_type variable for each client when the client connects, but the client may change its session variable value to use a different default table type.



          Session variables are set using syntax similar to that for setting global variables. For example, the default table type may be set either globally or only for the current connection using the following statements:










          mysql> SET GLOBAL table_type = MyISAM;

          mysql> SET @@global.table_type = MyISAM;



          mysql> SET SESSION table_type = InnoDB;

          mysql> SET @@session.table_type = InnoDB;




          LOCAL is a synonym for SESSION. Also, if you do not indicate explicitly whether to set the global or session version of a variable, MySQL sets the session variable. Each of these statements sets the session table_type variable:










          mysql> SET LOCAL table_type = InnoDB;

          mysql> SET @@local.table_type = InnoDB;

          mysql> SET table_type = InnoDB;

          mysql> SET @@table_type = InnoDB;




          To explicitly display global or session variable values, use SHOW GLOBAL VARIABLES or SHOW SESSION VARIABLES. Without GLOBAL or SESSION, the SHOW VARIABLES statement displays session values.



          It's also possible to use SELECT to display the values of individual global or session values:










          mysql> SELECT @@global.table_type, @@session.table_type;

          +---------------------+----------------------+

          | @@global.table_type | @@session.table_type |

          +---------------------+----------------------+

          | MYISAM | INNODB |

          +---------------------+----------------------+




          If @@ is not followed by a global or session scope specifier, the server returns the session variable if it exists and the global variable otherwise:










          mysql> SELECT @@table_type;

          +--------------+

          | @@table_type |

          +--------------+

          | INNODB |

          +--------------+




          The MySQL Reference Manual indicates which variables are dynamic and whether they have global or session forms.



          16.1.2 Accessing Server Status Information



          The server tracks many aspects of its own operation using a set of status variables. It makes the current values of these variables available through the SHOW STATUS statement, which you use much like SHOW VARIABLES:










          mysql> SHOW STATUS;

          +--------------------------------+------------+

          | Variable_name | Value |

          +--------------------------------+------------+

          | Aborted_clients | 160 |

          | Aborted_connects | 6 |

          | Bytes_received | 34971464 |

          | Bytes_sent | 43375040 |

          | Com_admin_commands | 15004 |

          ...




          To display only those variables with names that match a given pattern, add a LIKE pattern-matching clause. The pattern is not case sensitive and may contain the % and _ wildcard pattern metacharacters. For example, all query cache status variable names begin with Qcache and may be displayed as follows:










          mysql> SHOW STATUS LIKE 'qcache%';

          +-------------------------+--------+

          | Variable_name | Value |

          +-------------------------+--------+

          | Qcache_queries_in_cache | 360 |

          | Qcache_inserts | 12823 |

          | Qcache_hits | 21145 |

          | Qcache_lowmem_prunes | 584 |

          | Qcache_not_cached | 10899 |

          | Qcache_free_memory | 231008 |

          | Qcache_free_blocks | 98 |

          | Qcache_total_blocks | 861 |

          +-------------------------+--------+




          If the pattern contains no metacharacters, the statement displays only the named variable:










          mysql> SHOW STATUS LIKE 'Uptime';

          +---------------+---------+

          | Variable_name | Value |

          +---------------+---------+

          | Uptime | 5084640 |

          +---------------+---------+




          Status variables may be obtained in other ways as well. mysqladmin extended-status provides command-line access to the complete list of status variables, and mysqladmin status displays a brief summary. The MySQLCC graphical client provides access to status information in its server administration window.



          The following list indicates some of the ways you can use status information:



          • Several status variables provide information about how many connections the server is handling, including the number of successful and unsuccessful connection attempts, and also whether successful connections terminate normally or abnormally. From these variables, you can determine the following information:

            • The total number of connection attempts (both successful and unsuccessful):








              Connections


            • The number of unsuccessful connection attempts:








              Aborted_connects


            • The number of successful connection attempts:








              Connections - Aborted_connects


            • The number of successful connections that terminated abnormally (for example, if the client died or the network went down):








              Aborted_clients


            • The number of successful connections that terminated normally:








              Connections - Aborted_connects - Aborted_clients


            • The number of clients currently connected to the server:








              Threads_connected


          • The Com variables give you a breakdown of the number of queries the server has executed by statement type. You can see all these variables with the following statement:








            mysql> SHOW STATUS LIKE 'Com%';

            +------------------------+-------+

            | Variable_name | Value |

            +------------------------+-------+

            | Com_admin_commands | 0 |

            | Com_alter_table | 2 |

            | Com_analyze | 0 |

            | Com_backup_table | 0 |

            | Com_begin | 1 |

            | Com_change_db | 629 |

            | Com_change_master | 0 |

            ...


            Or you can name specific variables:








            mysql> SHOW STATUS LIKE 'Com_delete';

            +---------------+-------+

            | Variable_name | Value |

            +---------------+-------+

            | Com_delete | 315 |

            +---------------+-------+

            mysql> SHOW STATUS LIKE 'Com_update';

            +---------------+-------+

            | Variable_name | Value |

            +---------------+-------+

            | Com_update | 10691 |

            +---------------+-------+

            mysql> SHOW STATUS LIKE 'Com_select';

            +---------------+-------+

            | Variable_name | Value |

            +---------------+-------+

            | Com_select | 23727 |

            +---------------+-------+


            Com_select does not include the number of queries processed using the query cache because those queries are not executed in the usual sense. Their results are pulled directly from the query cache without consulting any tables. The number of such queries is given by the Qcache_hits status variable. See section 16.3, "Using the Query Cache."

          • The server caches open file descriptors when possible to avoid repeated file-opening operations, but a cache that's too small will not hold all the file descriptors you need. The Opened_tables variable indicates the number of times the server had to open files to access tables. It provides a measure of whether your table cache is large enough. See section 16.2, "Tuning Memory Parameters."

          • Bytes_received and Bytes_sent show the amount of traffic sent over the network.



          Status information can help you determine how smoothly the server is running or how well it's performing. Section 16.1.3, "Measuring Server Load," discusses some ways to use status variables to assess server load.



          16.1.3 Measuring Server Load



          Status information that the server provides can be used to assess how hard it's working:



          • Several status variables displayed by SHOW STATUS provide load information. For example, Questions indicates the number of queries the server has processed and Uptime indicates the number of seconds the server has been running. Combining these, the ratio Questions/Uptime tells you how many queries per second the server has processed.

          • Slow_queries indicates the number of queries that take a long time to process. Ideally, its value should increase slowly or not at all. If it increases quickly, you might have a problem with certain queries. The slow query log shows the text of slow queries and provides information about how long they took. Restart the server with the slow query log enabled, let it run for a while, and then take a look at the log to see which queries turn up there. You can use this log to identify queries that might need optimizing, as discussed in section 13.2.1, "Identifying Candidates for Query Analysis."

          • SHOW PROCESSLIST displays information about the activity of each currently connected client. For example, the presence of a large number of blocked queries might indicate that another connection is running a query that's inefficient and should be examined to see whether it can be optimized. The SHOW PROCESSLIST statement always shows your own queries. If you have the PROCESS privilege, it also shows queries being run by other accounts.

          • To get a concise report of the server's load status, invoke the mysql client program and use its STATUS (or \s) command to display a general snapshot of the current connection state. The last part of the output provides some information about the server load:








            mysql> STATUS;

            --------------

            mysql Ver 12.22 Distrib 4.0.16, for intel-linux (i686)



            Connection id: 34816

            Current database: world

            Current user: myname@localhost

            SSL: Not in use

            Current pager: stdout

            Using outfile: ''

            Server version: 4.0.16-log

            Protocol version: 10

            Connection: Localhost via UNIX socket

            Client characterset: latin1

            Server characterset: latin1

            UNIX socket: /tmp/mysql.sock

            Uptime: 51 days 3 hours 40 min 37 sec



            Threads: 4 Questions: 216232 Slow queries: 5 Opens: 652

            Flush tables: 6 Open tables: 64 Queries per second avg: 0.050

            --------------




          For a discussion of ways to reduce server load by helping it work more effectively, see sections 16.2, "Tuning Memory Parameters," and 16.3, "Using the Query Cache."



          16.1.4 Accessing Server Error Messages



          The preceding sections describe how to obtain information that the server provides during the course of its normal operation. The server also provides diagnostic information about exceptional conditions in the form of error messages:



          • On Windows, the server opens an error log file, which by default is named host_name.err in the data directory. (Older versions use the name mysql.err.) If you start the server from the command line with the --console option, it writes error information to the console window rather than to the error log.

          • On Unix, if you invoke mysqld directly, it sends diagnostics to its standard error output, which normally is your terminal. If you invoke the server using mysqld_safe (or mysql.server, which in turn invokes mysqld_safe), diagnostic output is redirected to an error log. By default, the error log name is host_name.err in the server's data directory.



          Diagnostic output produced by the server includes information about normal startup and shutdown. It also includes messages about abnormal execution conditions, such as the following:



          • Unrecognized startup options. If the server attempts to start up but quits almost immediately, you might have a bad option listed in an option file. The error log can tell you this.

          • Failure of the server to open its network interfaces: the TCP/IP port, the Windows named pipe, or the Unix socket file. The server cannot use an interface that is already in use by another server.

          • Storage engine initialization failure. This might occur due to incorrect configuration of the storage engine (for example, if a file specified as part of the InnoDB tablespace cannot be opened), or detection of conditions that make it impossible to continue (for example, if a storage engine detects table corruption but cannot correct it automatically).

          • Failure to find SSL certificate or key files that are named by startup options.

          • Inability of the server to change its user ID on Unix. This can happen if you specify a --user option but do not start the server as root so that it can relinquish root privileges and change to a different user.

          • Problems related to replication.



          On Unix, if the server was started by the mysqld_safe script, mysqld_safe itself may write information to the error log. For example, if mysqld_safe detects that the server has died, it automatically restarts the server after writing mysqld restarted to the log.













             < Day Day Up > 



            The Best Replacement for stop(), suspend(), and resume()




















            Chapter 5 - Gracefully Stopping Threads

            Java Thread Programming
            Paul
            Hyde






            size=1>  size=2>Copyright � 1999 Sams
            Publishing




















            size=4>The Best Replacement for stop(), suspend(), and
            resume()












            size=2>The class size=2>BestReplacement
            presented in Listing 5.11 combines some techniques from other
            chapters to create a model class that effectively eliminates the
            need for the three deprecated methods
            face="Courier New" size=2>stop() face=Arial size=2>, size=2>suspend(), and
            size=2>resume() size=2>.












            size=2>Listing 5.11  BestReplacement.java—Combined
            Alternative Techniques












            face="Courier New" size=2>  1: // uses BooleanLock from chapter
            17










            face="Courier New" size=2>  2:










            face="Courier New" size=2>  3: public class BestReplacement
            extends Object {










            face="Courier New" size=2>  4:     private
            Thread internalThread;










            face="Courier New" size=2>  5:     private
            volatile boolean stopRequested;










            face="Courier New" size=2>  6:










            face="Courier New" size=2>  7:     private
            BooleanLock suspendRequested;










            face="Courier New" size=2>  8:     private
            BooleanLock internalThreadSuspended;










            face="Courier New" size=2>  9:










            face="Courier New" size=2>10:     public
            BestReplacement() {










            face="Courier New"
            size=2>11:        
            stopRequested = false;










            face="Courier New" size=2>12:










            face="Courier New"
            size=2>13:        
            suspendRequested = new BooleanLock(false);










            face="Courier New"
            size=2>14:        
            internalThreadSuspended = new BooleanLock(false);










            face="Courier New" size=2>15:










            face="Courier New"
            size=2>16:         Runnable
            r = new Runnable() {










            face="Courier New"
            size=2>17:                
            public void run() {










            face="Courier New"
            size=2>18:                    
            try {










            face="Courier New"
            size=2>19:                        
            runWork();










            face="Courier New"
            size=2>20:                    
            } catch ( Exception x ) {










            face="Courier New"
            size=2>21:                        
            // in case ANY exception slips through










            face="Courier New"
            size=2>22:                        
            x.printStackTrace();










            face="Courier New"
            size=2>23:                    
            }










            face="Courier New"
            size=2>24:                
            }










            face="Courier New"
            size=2>25:            
            };










            face="Courier New" size=2>26:










            face="Courier New"
            size=2>27:        
            internalThread = new Thread(r);










            face="Courier New"
            size=2>28:        
            internalThread.start();










            face="Courier New" size=2>29:     }










            face="Courier New" size=2>30:










            face="Courier New" size=2>31:     private void
            runWork() {










            face="Courier New"
            size=2>32:         int count
            = 0;










            face="Courier New" size=2>33:










            face="Courier New"
            size=2>34:         while (
            !stopRequested ) {










            face="Courier New"
            size=2>35:            
            try {










            face="Courier New"
            size=2>36:                
            waitWhileSuspended();










            face="Courier New"
            size=2>37:            
            } catch ( InterruptedException x ) {










            face="Courier New"
            size=2>38:                
            // Reassert interrupt so that remaining code










            face="Courier New"
            size=2>39:                
            // sees that an interrupt has been requested.










            face="Courier New"
            size=2>40:                
            Thread.currentThread().interrupt();










            face="Courier New" size=2>41:










            face="Courier New"
            size=2>42:                
            // Reevaluate while condition --probably










            face="Courier New"
            size=2>43:                
            // false now.










            face="Courier New"
            size=2>44:                
            continue;










            face="Courier New"
            size=2>45:            
            }










            face="Courier New" size=2>46:










            face="Courier New"
            size=2>47:            
            System.out.println(“Part I - count=” + count);










            face="Courier New" size=2>48:










            face="Courier New"
            size=2>49:            
            try {










            face="Courier New"
            size=2>50:                
            Thread.sleep(1000);










            face="Courier New"
            size=2>51:            
            } catch ( InterruptedException x ) {










            face="Courier New"
            size=2>52:                
            Thread.currentThread().interrupt(); // reassert










            face="Courier New"
            size=2>53:                
            // continue on as if sleep completed normally










            face="Courier New"
            size=2>54:            
            }










            face="Courier New" size=2>55:










            face="Courier New"
            size=2>56:            
            System.out.println(“Part II - count=” + count);










            face="Courier New" size=2>57:










            face="Courier New"
            size=2>58:            
            try {










            face="Courier New"
            size=2>59:                
            Thread.sleep(1000);










            face="Courier New"
            size=2>60:            
            } catch ( InterruptedException x ) {










            face="Courier New"
            size=2>61:                
            Thread.currentThread().interrupt(); // reassert










            face="Courier New"
            size=2>62:                
            // continue on as if sleep completed normally










            face="Courier New"
            size=2>63:            
            }










            face="Courier New" size=2>64:










            face="Courier New"
            size=2>65:            
            System.out.println(“Part III - count=” + count);










            face="Courier New" size=2>66:










            face="Courier New"
            size=2>67:            
            count++;










            face="Courier New"
            size=2>68:        
            }










            face="Courier New" size=2>69:     }










            face="Courier New" size=2>70:










            face="Courier New" size=2>71:     private void
            waitWhileSuspended()










            face="Courier New"
            size=2>72:                    
            throws InterruptedException {










            face="Courier New" size=2>73:










            face="Courier New"
            size=2>74:         // only
            called by the internal thread - private method










            face="Courier New" size=2>75:










            face="Courier New"
            size=2>76:        
            synchronized ( suspendRequested ) {










            face="Courier New"
            size=2>77:            
            if ( suspendRequested.isTrue() ) {










            face="Courier New"
            size=2>78:                
            try {










            face="Courier New"
            size=2>79:                    
            internalThreadSuspended.setValue(true);










            face="Courier New"
            size=2>80:                    
            suspendRequested.waitUntilFalse(0);










            face="Courier New"
            size=2>81:                
            } finally {










            face="Courier New"
            size=2>82:                    
            internalThreadSuspended.setValue(false);










            face="Courier New"
            size=2>83:                
            }










            face="Courier New"
            size=2>84:            
            }










            face="Courier New"
            size=2>85:        
            }










            face="Courier New" size=2>86:     }










            face="Courier New" size=2>87:










            face="Courier New" size=2>88:     public void
            suspendRequest() {










            face="Courier New"
            size=2>89:        
            suspendRequested.setValue(true);










            face="Courier New" size=2>90:     }










            face="Courier New" size=2>91:










            face="Courier New" size=2>92:     public void
            resumeRequest() {










            face="Courier New"
            size=2>93:        
            suspendRequested.setValue(false);










            face="Courier New" size=2>94:     }










            face="Courier New" size=2>95:










            face="Courier New" size=2>96:     public boolean
            waitForActualSuspension(long msTimeout)










            face="Courier New"
            size=2>97:                    
            throws InterruptedException {










            face="Courier New" size=2>98:










            face="Courier New"
            size=2>99:         //
            Returns ‘true’ if suspended, ‘false’ if the










            face="Courier New"
            size=2>100:         //
            timeout expired.










            face="Courier New" size=2>104:










            face="Courier New" size=2>105:     public void
            stopRequest() {










            face="Courier New"
            size=2>106:        
            stopRequested = true;










            face="Courier New"
            size=2>107:        
            internalThread.interrupt();










            face="Courier New" size=2>108:     }










            face="Courier New" size=2>109:










            face="Courier New" size=2>110:     public
            boolean isAlive() {










            face="Courier New"
            size=2>111:         return
            internalThread.isAlive();










            face="Courier New" size=2>112:     }










            face="Courier New" size=2>113:










            face="Courier New" size=2>114:     public static
            void main(String[] args) {










            face="Courier New"
            size=2>115:         try
            {










            face="Courier New"
            size=2>116:            
            BestReplacement br = new BestReplacement();










            face="Courier New"
            size=2>117:            
            System.out.println(










            face="Courier New"
            size=2>118:                    
            “--> just created, br.isAlive()=” +










            face="Courier New"
            size=2>119:                    
            br.isAlive());










            face="Courier New"
            size=2>120:            
            Thread.sleep(4200);










            face="Courier New" size=2>121:










            face="Courier New"
            size=2>122:            
            long startTime = System.currentTimeMillis();










            face="Courier New"
            size=2>123:            
            br.suspendRequest();










            face="Courier New"
            size=2>124:            
            System.out.println(










            face="Courier New"
            size=2>125:                    
            “--> just submitted a suspendRequest”);










            face="Courier New" size=2>126:










            face="Courier New"
            size=2>127:            
            boolean suspensionTookEffect =










            face="Courier New"
            size=2>128:                    
            br.waitForActualSuspension(10000);










            face="Courier New"
            size=2>129:            
            long stopTime = System.currentTimeMillis();










            face="Courier New" size=2>130:










            face="Courier New"
            size=2>131:            
            if ( suspensionTookEffect ) {










            face="Courier New"
            size=2>132:                
            System.out.println(










            face="Courier New"
            size=2>133:                    
            “--> the internal thread took “ +










            face="Courier New"
            size=2>134:                    
            (stopTime - startTime) + “ ms to notice “ +










            face="Courier New"
            size=2>135:                    
            “\n    the suspend request and is now “ +










            face="Courier New"
            size=2>136:                    
            “suspended.”);










            face="Courier New"
            size=2>137:            
            } else {










            face="Courier New"
            size=2>138:                
            System.out.println(










            face="Courier New"
            size=2>139:                    
            “--> the internal thread did not notice “ +










            face="Courier New"
            size=2>140:                    
            “the suspend request “ +










            face="Courier New"
            size=2>141:                    
            “\n    within 10 seconds.”);










            face="Courier New"
            size=2>142:            
            }










            face="Courier New" size=2>143:










            face="Courier New"
            size=2>144:            
            Thread.sleep(5000);










            face="Courier New" size=2>145:










            face="Courier New"
            size=2>146:            
            br.resumeRequest();










            face="Courier New"
            size=2>147:            
            System.out.println(










            face="Courier New"
            size=2>148:                    
            “--> just submitted a resumeRequest”);










            face="Courier New"
            size=2>149:            
            Thread.sleep(2200);










            face="Courier New" size=2>150:










            face="Courier New"
            size=2>151:            
            br.stopRequest();










            face="Courier New"
            size=2>152:            
            System.out.println(










            face="Courier New"
            size=2>153:                    
            “--> just submitted a stopRequest”);










            face="Courier New"
            size=2>154:         } catch
            ( InterruptedException x ) {










            face="Courier New"
            size=2>155:            
            // ignore










            face="Courier New"
            size=2>156:        
            }










            face="Courier New" size=2>157:     }










            face="Courier New" size=2>158: }












            size=2>In writing size=2>BestReplacement,
            I used some techniques from other chapters. It is a
            color=#010100 face=Arial size=2>self-running
            object
            (for more
            details, see the technique in
            color=#008000 face=Arial size=2> Chapter 11, “Self-Running
            Objects”) in the
            sense that from outside the class, there is no indication that a
            thread will be running internally (although the class’s
            documentation should mention this fact). A user of this class does
            not have to create a thread to run within it; one is created (line
            27) and started (line 28) automatically in the constructor. The
            reference to this thread is held in a
            face="Courier New" size=2>private face=Arial size=2> member variable (line 4). The color=#000000 face="Courier New" size=2>Runnable color=#000000 face=Arial size=2> used by the internal thread is an
            inner class (lines 16–25). By using an inner class, the
            color=#000000 face="Courier New" size=2>public void
            run()
            method is hidden
            and cannot be erroneously called by external code. Within this inner
            class, the
            size=2>private void runWork() size=2> method is invoked by the internal thread (line 19). In your
            design, if the thread should not be started in the constructor, you
            can include another method to allow the
            face="Courier New" size=2>internalThread.start() color=#000000 face=Arial size=2> operation to be performed when
            appropriate.












            size=2>Additionally, the face="Courier New" size=2>BooleanLock face=Arial size=2> class is used from color=#008000 face=Arial size=2>Chapter 17 color=#000000 face=Arial size=2>. face="Courier New" size=2>BooleanLock face=Arial size=2> encapsulates the wait/notify mechanism inside a
            class that holds a
            size=2>boolean value.
            The
            size=2>setValue()
            method is used to change the internal value and signal any and all
            threads waiting for the value to change. Other threads can wait for
            the value to be changed by invoking methods like
            color=#000000 face="Courier New" size=2>waitUntilTrue() color=#000000 face=Arial size=2> and face="Courier New" size=2>waitUntilFalse() face=Arial size=2>. In size=2>BestReplacement,
            two instances of
            size=2>BooleanLock are
            used. The
            size=2>suspendRequested
            instance (line 7) is used to track whether a suspend has been
            requested. The
            size=2>internalThreadSuspended size=2> instance (line 8) is used to determine if the internal
            thread has noticed a suspend request. Both are initially set to
            size=2>false (lines
            13–14).












            size=2>Inside the size=2>runWork()
            method, the
            size=2>while loop
            (lines 34–68) continues until
            face="Courier New" size=2>stopRequested face=Arial size=2> is size=2>true. Each time
            through,
            size=2>waitWhileSuspended() size=2> is called (line 36) to block, if currently suspended. This
            is a
            safe
            place
            for the
            internal thread to be suspended or stopped. If the internal thread
            is interrupted while waiting, it will throw an
            color=#010100 face="Courier New"
            size=2>InterruptedException
            size=2>. The interrupt is used only to signal that the thread should
            die as soon as possible. This exception is caught, and the thread is
            reinterrupted (line 40) in case any other remaining statement
            becomes stuck and jumps back up to the top of the
            color=#010100 face="Courier New" size=2>while color=#010100 face=Arial size=2> because of the color=#010100 face="Courier New" size=2>continue color=#010100 face=Arial size=2> statement (line 44).












            size=2>If not currently suspended, or after being resumed, the
            internal thread proceeds through the statements and prints various
            messages (lines 47, 56, and 65). Several sleeps are used and if
            interrupted, catch the exception and reassert the interrupted status
            (lines 52 and 61).












            size=2>In size=2>suspendRequest() size=2>, the size=2>suspendRequested
            instance of
            size=2>BooleanLock has
            its value set to
            size=2>true (line 89).
            In
            size=2>resumeRequest(),
            size=2>suspendRequest
            is set to
            size=2>false (line 93).
            All of the synchronization and notification necessary for changing
            the value is encapsulated inside
            face="Courier New" size=2>BooleanLock face=Arial size=2>.












            size=2>In size=2>waitWhileSuspended() size=2> (lines 71–86), a busy wait is avoided by using a
            size=2>BooleanLock
            instance (
            size=2>BooleanLock uses
            the wait/notify mechanism internally). First, the internal thread
            blocks until it can acquire exclusive access to the object-level
            lock on
            size=2>suspendRequested
            (line 76). If it is currently suspended, it enters the
            color=#010100 face="Courier New" size=2>try color=#010100 face=Arial size=2>/ face="Courier New" size=2>finally face=Arial size=2> block (lines 77–84); otherwise, it simply
            returns. In the
            size=2>try/ color=#010100 face="Courier New" size=2>catch color=#010100 face=Arial size=2> block, the internal thread
            indicates that it has noticed the suspend request by setting the
            state of
            size=2>internalThreadSuspened size=2> to size=2>true (line 79).
            The internal thread then invokes the
            face="Courier New" size=2>waitUntilFalse() face=Arial size=2> method of face="Courier New" size=2>suspendRequested face=Arial size=2> with a timeout of face="Courier New" size=2>0 size=2> to indicate that it should never timeout (line 80). No
            matter what happens, when the internal thread leaves the
            try color=#010100 face=Arial size=2> section, it enters the color=#010100 face="Courier New" size=2>finally color=#010100 face=Arial size=2> section where the state of
            size=2>internalThreadSuspended size=2> is set back to size=2>false (line
            82).












            size=2>If an external thread wants to know if the internal thread
            has noticed the suspend request, the external thread can invoke
            size=2>waitForActualSuspension() face=Arial size=2> (lines 96–103). This blocks waiting (up to the
            timeout) until
            size=2>internalThreadSuspended size=2> is set to size=2>true.














              size=2>Tip size=2> size=2> color=#000000 face="Courier New" size=2> face=Arial size=2> color=#008000 face=Arial size=2> face=Arial size=2> color=#008000 face=Arial size=2> face=Arial size=2> color=#008000 face=Arial size=2> face=Arial size=2> size=2>Don’t
            worry if you don’t fully understand the use of
            color=#000000 face="Courier New" size=2>synchronized color=#000000 face=Arial size=2> and the wait/notify mechanism
            encapsulated in
            size=2>BooleanLock at
            this time. I fully explain them in
            color=#008000 face=Arial size=2>Chapters 7 color=#000000 face=Arial size=2>, color=#008000 face=Arial size=2>8 face=Arial size=2>, and color=#008000 face=Arial size=2>17 face=Arial size=2>.












            size=2>The internal thread can be stopped by invoking color=#010100 face="Courier New" size=2>stopRequest() color=#010100 face=Arial size=2>. This method first sets the
            size=2>stopRequest
            size=2>boolean flag to
            size=2>true (line 106).
            It then interrupts the internal thread to “unstick” it from any
            blocking sleeps or waits (line 107). The
            face="Courier New" size=2>isAlive() face=Arial size=2> method is used to check whether the internal
            thread has died (line 111).












            size=2>When run, output such as the following is produced:












            face="Courier New" size=2>--> just created,
            br.isAlive()=true










            face="Courier New" size=2>Part I - count=0










            face="Courier New" size=2>Part II - count=0










            face="Courier New" size=2>Part III - count=0










            face="Courier New" size=2>Part I - count=1










            face="Courier New" size=2>Part II - count=1










            face="Courier New" size=2>Part III - count=1










            face="Courier New" size=2>Part I - count=2










            face="Courier New" size=2>--> just submitted a
            suspendRequest










            face="Courier New" size=2>Part II - count=2










            face="Courier New" size=2>Part III - count=2










            face="Courier New" size=2>--> the internal thread took 1810 ms to
            notice










            face="Courier New" size=2>    the suspend request and
            is now suspended.










            face="Courier New" size=2>--> just submitted a
            resumeRequest










            face="Courier New" size=2>Part I - count=3










            face="Courier New" size=2>Part II - count=3










            face="Courier New" size=2>Part III - count=3










            face="Courier New" size=2>Part I - count=4










            face="Courier New" size=2>--> just submitted a
            stopRequest










            face="Courier New" size=2>Part II - count=4










            face="Courier New" size=2>Part III - count=4












            size=2>Notice that when a suspend request is submitted, the loop
            continues until the suspend check at the top (
            color=#010100 face="Courier New"
            size=2>waitWhileSuspended()
            size=2>). Also notice that when stopped, the internal thread does
            not immediately terminate, but instead finishes its tasks in an
            orderly manner.














              size=2>Caution size=2> size=2> color=#000000 face="Courier New" size=2> face=Arial size=2> size=2> color=#000000 face="I Frutiger Italic" size=2> color=#000000 face=Arial size=2> face="Courier New" size=2> size=2> color=#008000 face=Arial size=2> size=2>Keep in
            mind that this stopping feature requires that a blocked statement
            respond to an interrupt. This is not always the case. For example,
            the
            size=2>read() method on
            an
            size=2>InputStream
            blocks until a new byte is available, the end of stream is reached,
            or an
            size=2>IOException is
            thrown. It does
            size=2>not throw an
            size=2>InterruptedException size=2> if the blocked thread is interrupted! A technique for
            dealing with this situation is offered in
            color=#008000 face=Arial size=2>Chapter 15, “Breaking Out of a
            Blocked I/O State.”












            valign="top" bgcolor="#FFFFFF">

            Toc