XMLSERVICE/Toolkit debugging and service¶
Who is this page for?¶
Instructions designed for IBM i developer learning PHP and XMLSERVICE …
Debug technique: It’s as easy as 1-2-3-4-5-6-7-8-9 :)¶
- Run the test script that contains control “*debug” and script will “hang” while it waits on #2
$ctl .= " *debug";
- A MSGW inquiry message in DSPMSG QSYSOPR will be generated by the toolkit. Note the job information (number, name, user) provided in the MSGW.
- STRSRVJOB using that job information as parameters.
- STRDBG with the program and library you wish to debug.
- Answer the MSGW. Any answer will do–“G” is fine.
- The RPG program source will appear in debug mode in your terminal, ready to step through, allowing you to inspect variables, etc.
- When done inspecting and stepping, let the RPG program complete (using function keys indicated on screen).
- ENDDBG
- ENDSRVJOB
Other debug options:
Job1 (threaded) Job 2 Job 3 (DB2 userid/password) Job 4 (optional XTOOLKIT job)
(ctl=*debugcgi) (ctl=*debugproc) (ctl=*debug)
browser -> Apache ->XMLCGI (Apache CGI child) -> QSQSRVR (XMLSERVICE *here)
-> QSQSRVR (XMLSERVICE client) -> XTOOLKIT (XMLSERVICE ipc=/tmp/flinstone)
$ctl .= " *debugcgi"; // Job 2 - debug XMLCGI to see REST/HTTP data passed by client (when using REST only)
$ctl .= " *debugproc"; // Job 3 - debug XMLSERVICE "client" to see DB2 passed data (DB2 interface)
$ctl .= " *debug"; // Job 4 - debug XMLSERVICE "server" to see XMLSERVICE calls (DB2 interface)
// Note: when ctl='*here', both XMLSERVICE "client"/"server"
// are in QSQSRVSR job (NO XTOOLKIT job)
// remote: Attaching with LUW drivers changes QSQSRVR ...
// CLIENT (Client Access drivers) <==> QZDAxxxx
// CLIENT (DB2 Connect drivers) <==> QRWxxxx
Working with service provider?¶
Here are a few common things that can provide useful information if working with outside support people.
- easy way 1.7.1 … just send provider XMLSERVLOG/LOG and XMLSERVLOG/DUMP in SAVF
assuming you have a trace of the issue (see xmlservice logging instructions)
- what do you see in error logs for simple tests ???
call qp2term
> tail /usr/local/zendsvr/var/log/php.log
> tail /myasp2/www/zend2/logs/error_log.Q112061800
> tail /myasp2/www/zend2/logs/access_log.Q112061800
- Summarize configuration (below)???
My Example
SYSASP -- ZENDSVR library ... everything as installed SYSASP -- /usr/local/zendsvr ... everything as installed SYSASP -- /tmp ... many Zend "enterprise" components use /tmp MYASP2 -- /myasp2/www/zend2 ... ALL "user data" moved from /www/zendsvr (/conf, /logs, /htdocs) More ... /myasp2/www/zend2 -- NO symbolic links between SYSAPS and MYASP2 for true "independent"ASP. -- config files /myasp2/www/zend2/conf attach: fastcgi.conf attach: httpd.conf
- Around time of simple test failure … do you see job logs?
wrkoutq
If jobs are still active (php-cgi, etc.) ... wrkactjob 5 ZEND2 QTMHHTTP BCI .0 PGM-QZSRHTTP SIGW ZEND2 QTMHHTTP BCI .0 PGM-php-cgi.bi THDW 5 ZEND2 QTMHHTTP BCI .0 PGM-php-cgi.bi TIMW 10. Display job log, if active, on job queue, or pending F10 -- full job log
- Around time of simple test failure … do you see VLOGS???
STRSST 1. Start a service tool 5. Licensed Internal Code log 1. Select entries from the Licensed Internal Code (LIC) log Specify Licensed Internal Code Log Selection Values -- leave as is enter --- 0100A890 i5/OS PASE 4700 0013 06/15/12 09:03:43 7 <--- PASE 0100A891 LIC log interface 0401 0100 06/15/12 09:04:08 1 0100A892 Signals management 4600 0001 06/15/12 09:04:51 255 0100A893 Process management 1300 0001 06/18/12 21:02:06 1Maybe look for PASE, storage management, ASP, so on around “failure time”
Note: You can also dump logs to spool …
When you have no idea (dumping many processes)?¶
Some times you just have no idea what is going on, here is a handy macro to dump a lot of stacks.
STRSST/STRDST 1. Start a service tool 4. Display/Alter/Dump 1. Display/Alter storage ... or option for dump to printer ... 2. Licensed Internal Code (LIC) data 14. Advanced analysis Option Command 1 processinfo In this case dumping all process dealing with keyword "ZEND" appearing in job ... Specify Advanced Analysis Options Output device . . . . . . : Display Type options, press Enter. Command . . . . : PROCESSINFO Options . . . . . -NAMES ZENDNote: Information dumped printer/display is same as paseps macro.
Check active XMLSERVICE job¶
If you are using private connections (InternalKey or $ipc=’/tmp/packers’), the XMLSERVICE job is probably available for examination with wrkactjob.
Work with Active Jobs LP0264D
05/17/12 11:35:12
CPU %: .0 Elapsed time: 00:00:00 Active jobs: 313
Type options, press Enter.
2=Change 3=Hold 4=End 5=Work with 6=Release 7=Display message
8=Work with spooled files 13=Disconnect ...
Current
Opt Subsystem/Job User Type CPU % Function Status
5 XTOOLKIT DB2 BCH .0 PGM-XMLSERVICE SEMW
- Use
option 5=work -> 10. Display job log -> F10=Display detailed messages
to examine joblog on errors …
Display All Messages
System: LP0264D
Job . . : XTOOLKIT User . . : DB2 Number . . . : 435915
>> CALL PGM(XMLSERVICE/XMLSERVICE) PARM('/tmp/packers')
Pointer not set for location referenced.
Application error. MCH3601 unmonitored by ZZSRV at statement 0000000448,
instruction X'0000'.
- Use
option 5=work -> 11. Display call stack -> F5=Refresh
to examine stack during stress tests …
Display Call Stack
System: LP0264D
Job: XTOOLKIT User: DB2 Number: 437582
Thread: 0000000C
Type Program Statement Procedure
1 QCMD QSYS /01C8
XMLSERVICE XMLSERVICE _QRNP_PEP_XMLSERVICE
XMLSERVICE XMLSERVICE 1133 XMLSERVICE
XMLSERVICE XMLSERVICE 4607 RUNSERVER
XMLSERVICE XMLSERVICE 2983 SIGSETTIMEOUT
XMLSERVICE XMLSERVICE 2876 SIGTIMEROFF
QP0SSRV1 QSYS 19 setitimer
QP0SSRV2 QSYS 159 qp0sitimer__F12qp0sitimer_t >
Check the logs¶
Check PHP log for messages¶
On my IBM i machine:
EDTF STMF('/usr/local/zendsvr/var/log/php.log')
-- or --
call qp2term (or ssh myibmi)
> tail /usr/local/zendsvr/var/log/php.log
... stuff
... in /MYASP2/www/zend2/htdocs/hello.php on line 1
On my Linux machine:
$ tail /usr/local/zend/var/log/php.log
[16-May-2012 16:30:12] PHP Warning: db2_close() expects parameter 1 to be resource ...
Check Apache logs for messages¶
error logs for date in question:
EDTF STMF('/myasp2/www/zend2/logs/error_log.Q112051500')
-- or --
call qp2term (or ssh myibmi)
> tail /myasp2/www/zend2/logs/error_log.Q112051500
[Tue May 15 17:10:11 2012] [error] [client 9.5.158.38] CGI PROGRAM /QSYS.LIB/XMLSERVICE.LIB/XMLCGI.PGM RETURNED EXCEPTION ID CEE9901
[Tue May 15 17:10:11 2012] [error] [client 9.5.158.38] SEE JOBLOG FOR JOB 428979/QTMHHTTP /ZEND2
access logs for date in question:
EDTF STMF('/myasp2/www/zend2/logs/access_log.Q112051500')
-- or --
call qp2term (or ssh myibmi)
> tail /myasp2/www/zend2/logs/access_log.Q112051500
9.5.158.38 - - [15/May/2012:17:47:41 -0500] "GET /cgi-bin/xmlcgi.pgm?db2=LP0264D
Check PHP Toolkit logs for messages¶
toolkit.ini logfile
EDTF STMF('/usr/local/zendsvr/share/ToolkitApi/toolkit.log')
-- or --
call qp2term (or ssh myibmi)
> tail /usr/local/zendsvr/share/ToolkitAPI/toolkit.log
15 May 2012 22:53:35.752099 Running stateless; no IPC needed. Service library: ZENDSVR
15 May 2012 22:53:36.588466 i5Error: num=14 cat=9 msg="No more entries." desc="No more entries."
location set in toolkit.ini ...
EDTF STMF('/usr/local/zendsvr/share/ToolkitApi/toolkit.ini')
[log]
; warnings and errors will be written to the logfile.
logfile = "/usr/local/zendsvr/share/ToolkitApi/toolkit.log"
toolkit.ini debugLogFile
EDTF STMF('/usr/local/zendsvr/share/ToolkitApi/debug.log')
-- or --
call qp2term (or ssh myibmi)
> tail /usr/local/zendsvr/share/ToolkitAPI/debug.log
<data type='1A' var='ds1' comment='DSCHARA'><![CDATA[E]]></data>
<data type='1A' var='ds2' comment='DSCHARB'><![CDATA[F]]></data>
location set in toolkit.ini ...
EDTF STMF('/usr/local/zendsvr/share/ToolkitApi/toolkit.ini')
; debug turns PHP toolkit's debug mode on or off (true/false). Default log file: /usr/local/zendsvr/share/ToolkitApi/debug.log
; This log will grow large, so leave this false when you do not need to log everything.
debug = true
debugLogFile = "/usr/local/zendsvr/share/ToolkitApi/debug.log"
PHP and XMLSERVICE bad XML
EDTF STMF('/tmp/bad.xml')
-- or --
> tail /tmp/bad.xml
start
<?xml version="1.0" encoding="ISO-8859-1" ?><script><cmd><success><ܬCDATA�+++ success QSYS/DLTDTAARA DTAARA(XMLSERVICE/BETTYBOOP)||></success></cmd>
Check one level at a time¶
Troubles on your PHP site or installation???
Often times if you take a deep breath, slow down and look at each level of web site components you can find your issue without reaching for the bat phone and calling Zend or IBM. The following set of tests walks up the PHP levels of components to give you confidence you are looking at the correct layer of your issue. Of course after you complete smaller PHP scripts (hello.php, etc.), you can likely use the same step up next level techniques on your sophisticated applications (WorldPeace.php).
Level 0 – PHP Working¶
If you are running on the IBM i machine it is always best to make sure your Apache/PHP setup can do anything.
Note: Your machine may have document root at /www/zendsvr vs. /MYASP2/www/zend2 (out-of-box installed Zend Server).
Test number #0
Install the following simple test in your Document root and see if “Hello World” appears.
/MYASP2/www/zend2/htdocs/hello.php
<?php
echo "Hello world";
?>
Run the test:
call qp2term (or ssh myibmi)
> export PATH=/usr/local/zendsvr/bin:$PATH
> export LIBPATH=/usr/local/zendsvr/lib
> cd /MYASP2/www/zend2/htdocs
> php hello.php
Hello world>
Level 1 – Apache/PHP working¶
If you are running on the IBM i machine it is always best to make sure your Apache/PHP setup can do anything.
Note: Your machine may have document root at /www/zendsvr vs. /MYASP2/www/zend2 (out-of-box installed Zend Server).
Test number #1
Install the following simple test in your Document root and see if “Hello World” appears in your browser.
/MYASP2/www/zend2/htdocs/hello.php
<?php
echo "Hello world";
?>
Ok, next run stress test …
call qp2term
> cd /usr/local/Zend/apache2/bin
> ab -t 25 -c 10 http://myibmi/hello.php
-t 25 -- 25 seconds
-c 10 -- 10 concurrent browsers (simulates ten browsers)
- this test is designed to drive CPU to 100% (a good thing), so don’t panic about CPU
wrkactjob refresh (F10) - if you do not see multiple php-cgi jobs getting CPU re-run tests with more load
call qp2term
> cd /usr/local/Zend/apache2/bin
> ab -t 25 -c 10 http://myibmi/hello.php &; ab -t 25 -c 10 http://myibmi/hello.php &; ab -t 25 -c 10 http://myibmi/hello.php &;
-t 25 -- 25 seconds
-c 10 -- 10 concurrent browsers (simulates ten browsers)
Multiply by 3 Apache ab jobs running background -- 30 concurrent browsers (simulates thirty browsers)
- above using “&;” to fork/exec into background/batch many jobs(s) Apache ab to really hammer your web site
- ab tool is not perfect, so if you start too many of these forked jobs (’&;’) the tool may core dump (die) – i usually can get 3 - 6 jobs working (30-60 browsers)
- if you still do not see a split of CPU between php-cgi jobs you may be missing HTTP PTFS
Level 2 – db2 connection working¶
At this level we want to check our DB2 connections.
Note:
- Your machine may have document root at /www/zendsvr vs. /MYASP2/www/zend2 (out-of-box installed Zend Server).
- This same test can be run 2-tier from Linux/Windows to IBM i using DB2 Connect
Test number #2
Install the following simple test in your Document root and see if “success” appears in your browser.
/MYASP2/www/zend2/htdocs/connection2.inc
<?php
$database = "*LOCAL"; // *LOCAL on IBM i ... LP0264D on Linux
$cwdatabase = "localhost";
$user = "DB2";
$password = "XXXXXXXX";
$libxmlservice = "ZENDSVR"; // ZZCALL (Zend Server)
$i5persistentconnect = false;
?>
/MYASP2/www/zend2/htdocs/xxtoolkit_connect.php
<?php
require_once('connection2.inc');
// flip between persistent and non-persistent connections
for ($i=0;$i<500;$i++) {
for ($i5persistentconnect=1;$i5persistentconnect>-1;$i5persistentconnect--) {
if ($i5persistentconnect) $conn = db2_pconnect($database,$user,$password);
else $conn = db2_connect($database,$user,$password);
if (!$conn) echo "<br>Bad connect: $conn,$database,$user,perm=$i5persistentconnect";
else echo "<br>Good connect: $conn,$database,$user,perm=$i5persistentconnect";
if ($i5persistentconnect) $ok = true;
else $ok = db2_close($conn);
echo ",ok=$ok\n";
}
}
run the test Apache …
Point your browser to php program ...
http://myibmi/xxtoolkit_connect.php
Good connect: Resource id #2,*LOCAL,DB2,perm=1,ok=1
Good connect: Resource id #3,*LOCAL,DB2,perm=0,ok=1
Good connect: Resource id #4,*LOCAL,DB2,perm=1,ok=1
:
run the test 2-tier … I choose to run from command line on my Linux machine, but Linux Apache would also work.
$ which php
/usr/local/zend/bin/php
$ php xxtoolkit_connect.php
<br>Good connect: Resource id #5,LP0264D,DB2,perm=1,ok=1
<br>Good connect: Resource id #6,LP0264D,DB2,perm=0,ok=1
<br>Good connect: Resource id #7,LP0264D,DB2,perm=1,ok=1
:
Level 3 - XMLSERVICE XML interface Working¶
At this level we want to check our PHP raw XML Toolkit built on top of ibm_db2 connections (Level 2).
Note:
- Your machine may have document root at /www/zendsvr vs. /MYASP2/www/zend2 (out-of-box installed Zend Server).
- This same test can be run 2-tier from Linux/Windows to IBM i using DB2 Connect.
- RPG test *PGM ZENDSVR/ZZCALL is included with Zend Server installation, so test will run out-of-box
Test number #3
Install the following simple test in your Document root and see if “success” appears in your browser.
/MYASP2/www/zend2/htdocs/connection2.inc
<?php
$database = "*LOCAL"; // *LOCAL on IBM i ... LP0264D on Linux
$cwdatabase = "localhost";
$user = "DB2";
$password = "XXXXXXXX";
$libxmlservice = "ZENDSVR"; // ZZCALL (Zend Server)
$i5persistentconnect = false;
?>
/MYASP2/www/zend2/htdocs/xxtoolkit_raw.php
<?php
require_once('connection2.inc');
if ($i5persistentconnect) $conn = db2_pconnect($database,$user,$password);
else $conn = db2_connect($database,$user,$password);
if (!$conn) echo "Bad connect: $conn,$database,$user,perm=$i5persistentconnect";
$stmt = db2_prepare($conn, "call XMLSERVICE.iPLUG4K(?,?,?,?)");
$ctl = "*sbmjob"; // *here for no additional private job
$ipc='/tmp/packers';
// $ipc = ""; // *here no need ipc
$clobIn = "<?xml version='1.0'?>
<pgm name='ZZCALL' lib='$libxmlservice'>
<parm io='both'>
<data type='1A'>a</data>
</parm>
<parm io='both'>
<data type='1A'>b</data>
</parm>
<parm io='both'>
<data type='7p4'>11.1111</data>
</parm>
<parm io='both'>
<data type='12p2'>222.22</data>
</parm>
<parm io='both'>
<ds>
<data type='1A'>x</data>
<data type='1A'>y</data>
<data type='7p4'>66.6666</data>
<data type='12p2'>77777.77</data>
</ds>
</parm>
<return>
<data type='10i0'>0</data>
</return>
</pgm>";
$clobOut = "";
$ret=db2_bind_param($stmt, 1, "ipc", DB2_PARAM_IN);
$ret=db2_bind_param($stmt, 2, "ctl", DB2_PARAM_IN);
$ret=db2_bind_param($stmt, 3, "clobIn", DB2_PARAM_IN);
$ret=db2_bind_param($stmt, 4, "clobOut", DB2_PARAM_OUT);
$ret=db2_execute($stmt);
// var_dump($clobOut);
if (strpos($clobOut,"4444444444.44")>0) echo "success";
else echo "fail";
?>
run the test Apache …
Point your browser to php program ...
http://myibmi/xxtoolkit_raw.php
success
run the test 2-tier … I choose to run from command line on my Linux machine, but Linux Apache would also work.
$ which php
/usr/local/zend/bin/php
$ php xxtoolkit_raw.php
success
Ok, next run stress test …
call qp2term
> cd /usr/local/Zend/apache2/bin
> ab -t 25 -c 10 http://lp0264d/xxtoolkit_raw.php
-t 25 -- 25 seconds
-c 10 -- 10 concurrent browsers (simulates ten browsers)
- this test is designed to drive CPU to 100% (a good thing), so don’t panic about CPU
Level 4 – PHP New Toolkit working¶
At this level we want to check our PHP CW Toolkit built on top of raw XML Toolkit (Level 3).
Note:
- Your machine may have document root at /www/zendsvr vs. /MYASP2/www/zend2 (out-of-box installed Zend Server).
- This same test can be run 2-tier from Linux/Windows to IBM i using DB2 Connect.
- RPG test *PGM ZENDSVR/ZZCALL is included with Zend Server installation, so test will run out-of-box
Test number #4
Install the following simple test in your Document root and see if “success” appears in your browser.
/MYASP2/www/zend2/htdocs/connection2.inc
<?php
$database = "*LOCAL"; // *LOCAL on IBM i ... LP0264D on Linux
$cwdatabase = "localhost";
$user = "DB2";
$password = "XXXXXXXX";
$libxmlservice = "ZENDSVR"; // ZZCALL (Zend Server)
$i5persistentconnect = false;
?>
/MYASP2/www/zend2/htdocs/xxtoolkit_new.php
<?php
require_once('connection2.inc');
require_once("ToolkitService.php");
if ($i5persistentconnect) $conn = db2_pconnect($database,$user,$password);
else $conn = db2_connect($database,$user,$password);
if (!$conn) echo "Bad connect: $conn,$database,$user,perm=$i5persistentconnect";
try { $ToolkitServiceObj = ToolkitService::getInstance($conn); }
catch (Exception $e) { die($e->getMessage()); }
$param[] = $ToolkitServiceObj->AddParameterChar ('both', 1, 'INCHARA', 'var1', 'Y');
$param[] = $ToolkitServiceObj->AddParameterChar ('both', 1, 'INCHARB', 'var2', 'Z');
$param[] = $ToolkitServiceObj->AddParameterPackDec('both', 7,4,'INDEC1', 'var3', '001.0001');
$param[] = $ToolkitServiceObj->AddParameterPackDec('both', 12,2,'INDEC2', 'var4', '0000000003.04');
$ds[] = $ToolkitServiceObj->AddParameterChar ('both', 1, 'DSCHARA', 'ds1', 'A');
$ds[] = $ToolkitServiceObj->AddParameterChar ('both', 1, 'DSCHARB', 'ds2', 'B');
$ds[] = $ToolkitServiceObj->AddParameterPackDec('both', 7,4,'DSDEC1', 'ds3', '005.0007');
$ds[] = $ToolkitServiceObj->AddParameterPackDec('both', 12,2,'DSDEC1', 'ds4', '0000000006.08');
$param[] = $ToolkitServiceObj->AddDataStruct($ds);
$clobOut = $ToolkitServiceObj->PgmCall('ZZCALL', $libxmlservice, $param, null, null);
// var_dump($clobOut);
$value = "what is ...".$clobOut["io_param"]["ds4"];
if (strpos($value,"4444444444.44")>-1) echo "success";
else echo "fail";
run the test Apache …
Point your browser to php program ...
http://myibmi/xxtoolkit_new.php
success
run the test 2-tier … I choose to run from command line on my Linux machine, but Linux Apache would also work.
$ which php
/usr/local/zend/bin/php
$ php xxtoolkit_new.php
success
Ok, next run stress test …
call qp2term
> cd /usr/local/Zend/apache2/bin
> ab -t 25 -c 10 http://lp0264d/xxtoolkit_new.php
-t 25 -- 25 seconds
-c 10 -- 10 concurrent browsers (simulates ten browsers)
- this test is designed to drive CPU to 100% (a good thing), so don’t panic about CPU
Level 5 – PHP CW Toolkit working (optional)¶
At this level we want to check our PHP CW Toolkit built on top of new Toolkit (Level 4).
Note:
- Your machine may have document root at /www/zendsvr vs. /MYASP2/www/zend2 (out-of-box installed Zend Server).
- This same test can be run 2-tier from Linux/Windows to IBM i using DB2 Connect.
- RPG test *PGM ZENDSVR/ZZCALL is included with Zend Server installation, so test will run out-of-box
Test number #5
Install the following simple test in your Document root and see if “success” appears in your browser.
/MYASP2/www/zend2/htdocs/connection2.inc
<?php
$database = "*LOCAL"; // *LOCAL on IBM i ... LP0264D on Linux
$cwdatabase = "localhost";
$user = "DB2";
$password = "XXXXXXXX";
$libxmlservice = "ZENDSVR"; // ZZCALL (Zend Server)
$i5persistentconnect = false;
?>
/MYASP2/www/zend2/htdocs/xxtoolkit_cw.php
<?php
require_once('connection2.inc');
require_once('CW/cw.php'); // new toolkit compatibility (Alan)
/* connect */
if ($i5persistentconnect) $conn = i5_pconnect($cwdatabase,$user,$password);
else $conn = i5_connect($cwdatabase,$user,$password);
if (!$conn) echo "Bad connect: $conn,$cwdatabase,$user,perm=$i5persistentconnect";
if (!$conn)
{ $tab = i5_error();
die("fail Connect: ".$tab[2]." "."$tab[3], $tab[0]");
}
/* prepare */
$description =
array
(
// single parms
array
( "Name"=>"INCHARA","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_CHAR,"Length"=>"1"),
array
( "Name"=>"INCHARB","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_CHAR,"Length"=>"1"),
array
( "Name"=>"INDEC1","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_PACKED,"Length"=>"7.4"),
array
( "Name"=>"INDEC2","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_PACKED,"Length"=>"12.2"),
// structure parm
array
( "DSName"=>"INDS1",
"Count"=>1,
"DSParm"=>
array
(
array
( "Name"=>"DSCHARA","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_CHAR,"Length"=>"1"),
array
( "Name"=>"DSCHARB","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_CHAR,"Length"=>"1"),
array
( "Name"=>"DSDEC1","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_PACKED,"Length"=>"7.4"),
array
( "Name"=>"DSDEC2","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_PACKED,"Length"=>"12.2"),
)
)
);
$pgm = i5_program_prepare("$libxmlservice/ZZCALL", $description);
if (!$pgm)
{ $tab = i5_error();
die("fail Prepare: ".$tab[2]." "."$tab[3], $tab[0]");
}
// *** parameter list allocation
$list=
array
(
"DSCHARA"=>"x",
"DSCHARB"=>"y",
"DSDEC1"=>66.6666,
"DSDEC2"=>77777.77,
);
// *** parameter values passed to procedure
$in =
array
(
"INCHARA"=>"a",
"INCHARB"=>"b",
"INDEC1"=>11.1111,
"INDEC2"=>222.22,
"INDS1"=>$list,
);
// *** name of variables created for out parameters
$out =
array
(
"INCHARA"=>"INCHARA",
"INCHARB"=>"INCHARB",
"INDEC1"=>"INDEC1",
"INDEC2"=>"INDEC2",
"INDS1"=>"INDS1",
);
$rc=i5_program_call($pgm, $in, $out);
if ($rc != false)
{
if ($INCHARA != 'C') die("fail C == $INCHARA\n");
if ($INCHARB != 'D') die("fail D == $INCHARB\n");
if ($INDEC1 != 321.1234) die("fail 321.1234 == $INDEC1\n");
if ($INDEC2 != 1234567890.12) die("fail 1234567890.12 = $INDEC2\n");
if ($INDS1["DSCHARA"] != 'E'
|| $INDS1["DSCHARB"] != 'F'
|| $INDS1["DSDEC1"] != 333.333
|| $INDS1["DSDEC2"] != 4444444444.44)
{
var_dump($INDS1);
die("fail DS not correct\n");
}
}
else
{ $tab = i5_error();
die("fail Call: ".$tab[2]." "."$tab[3], $tab[0]");
}
// good
echo "success";
?>
run the test Apache …
Point your browser to php program ...
http://myibmi/xxtoolkit_cw.php
success
run the test 2-tier … I choose to run from command line on my Linux machine, but Linux Apache would also work.
$ which php
/usr/local/zend/bin/php
$ php xxtoolkit_cw.php
success
Ok, next run stress test …
call qp2term
> cd /usr/local/Zend/apache2/bin
> ab -t 25 -c 10 http://lp0264d/xxtoolkit_cw.php
-t 25 -- 25 seconds
-c 10 -- 10 concurrent browsers (simulates ten browsers)
- this test is designed to drive CPU to 100% (a good thing), so don’t panic about CPU
Apache ab sample running¶
Apache ab web site stress tests are performed from the 5250 command line (call qp2term) or ssh myibmi using PASE.
- You can run stress tests from 2-tier Linux/Windows using Apache ab tool, but i am using Apchae ab from PASE.
- Apache ab tool is not perfect, but if you use relatively “sane” number of browsers like -c 10 it will work.
- Apache ab test is designed to drive CPU to 100% (a good thing), so don’t panic about CPU
Example run my machine …
> ab -t 25 -c 10 http://lp0264d/hello.php
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking lp0264d (be patient)
Completed 5000 requests
Completed 10000 requests
Completed 15000 requests
Completed 20000 requests
Finished 20325 requests
Server Software: Apache
Server Hostname: lp0264d
Server Port: 80
Document Path: /hello.php
Document Length: 11 bytes
Concurrency Level: 10
Time taken for tests: 25.5119 seconds
Complete requests: 20325
Failed requests: 0
Write errors: 0
Total transferred: 3394275 bytes
HTML transferred: 223575 bytes
Requests per second: 812.83 [#/sec] (mean) <--- 800 hits/second
Time per request: 12.303 [ms] (mean)
Time per request: 1.230 [ms] (mean, across all concurrent requests)
Transfer rate: 132.53 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 1.1 0 30
Processing: 2 11 7.2 10 322
Waiting: 2 10 7.2 10 322
Total: 2 11 7.3 11 322
Percentage of the requests served within a certain time (ms)
50% 11
66% 12
75% 14
80% 15
90% 17
95% 19
98% 21
99% 23
100% 322 (longest request)
>
wrkactjob – during Apache ab test you can use refresh on wrkactjob scree to see the php-cgi jobs working
- you should expect to see multiple php-cgi jobs getting some CPU time as you refresh with F10
Work with Active Jobs LP0264D
05/16/12 13:37:25
CPU %: 100.0 Elapsed time: 00:00:00 Active jobs: 295
Type options, press Enter.
2=Change 3=Hold 4=End 5=Work with 6=Release 7=Display message
8=Work with spooled files 13=Disconnect ...
Current
Opt Subsystem/Job User Type CPU % Function Status
ZEND2 QTMHHTTP BCI .0 PGM-zfcgi SELW
ZEND2 QTMHHTTP BCI .0 PGM-php-cgi.bi THDW
ZEND2 QTMHHTTP BCI .0 PGM-php-cgi.bi THDW
ZEND2 QTMHHTTP BCI 2.8 PGM-php-cgi.bi TIMA
ZEND2 QTMHHTTP BCI 1.8 PGM-php-cgi.bi TIMA
ZEND2 QTMHHTTP BCI 2.3 PGM-php-cgi.bi TIMA
ZEND2 QTMHHTTP BCI 2.8 PGM-php-cgi.bi TIMA
ZEND2 QTMHHTTP BCI 1.8 PGM-php-cgi.bi RUN
ZEND2 QTMHHTTP BCI 1.4 PGM-php-cgi.bi TIMA
Stop XMLSERVICE for debugger attach¶
WRKACTJOB find XMLSERVICE private mode only¶
IF you are running a private connection (ipc=’/tmp/packers’), you can simply use WRKACTJOB and locate the XMLSERVICE job and attach debugger. However the next qsysopr message option is also available.
XMLSERVICE QSYSOPR message stop anytime¶
At times it is useful to stop the XMLSERVICE job to connect a debugger to examine an issue, especially if you are running stateless in the QSQSRVR job.
I often find the simple trick below to be very useful.
The trick …
At this time the PHP wrappers have not implemented a stop for debugger interface (cough … Alan),
but XMLSERVICE has control *debug ability already available. In the following example adding
$ctl .= " *debug";
will stop XMLSERVICE job with a inquire message on qsysopr,
simply attach your debugger to job # in msg, set a breakpoint in your module (or in XMLSERVICE module),
and answer qsysopr message with any character to let XMLSERVICE continue to your breakpoint. That is it …
Hint: PHP wrappers are sending XML just like below, so if you have toolkit.ini debug turned on you can often simply cut/paste your XML in debug log into the variable $clobIn below.
Test #3 as example …
/MYASP2/www/zend2/htdocs/connection2.inc
<?php
$database = "*LOCAL"; // *LOCAL on IBM i ... LP0264D on Linux
$cwdatabase = "localhost";
$user = "DB2";
$password = "XXXXXXXX";
$libxmlservice = "ZENDSVR"; // ZZCALL (Zend Server)
$i5persistentconnect = false;
?>
/MYASP2/www/zend2/htdocs/xxtoolkit_raw.php
<?php
require_once('connection2.inc');
if ($i5persistentconnect) $conn = db2_pconnect($database,$user,$password);
else $conn = db2_connect($database,$user,$password);
if (!$conn) echo "Bad connect: $conn,$database,$user,perm=$i5persistentconnect";
$stmt = db2_prepare($conn, "call XMLSERVICE.iPLUG4K(?,?,?,?)");
$ctl = "*sbmjob"; // *here for no additional private job
$ctl .= " *debug"; // THIS WILL STOP XMLSERVICE JOB MSG TO QSYSOPR (server side)
// $ctl .= " *debugproc"; // THIS WILL STOP XMLSERVICE/QSQSRVR JOB MSG TO QSYSOPR (client side)
// if running *here either *debug/*debugproc will work
$ipc='/tmp/packers';
// $ipc = ""; // *here no need ipc
$clobIn = "<?xml version='1.0'?>
<pgm name='ZZCALL' lib='$libxmlservice'>
<parm io='both'>
<data type='1A'>a</data>
</parm>
<parm io='both'>
<data type='1A'>b</data>
</parm>
<parm io='both'>
<data type='7p4'>11.1111</data>
</parm>
<parm io='both'>
<data type='12p2'>222.22</data>
</parm>
<parm io='both'>
<ds>
<data type='1A'>x</data>
<data type='1A'>y</data>
<data type='7p4'>66.6666</data>
<data type='12p2'>77777.77</data>
</ds>
</parm>
<return>
<data type='10i0'>0</data>
</return>
</pgm>";
$clobOut = "";
$ret=db2_bind_param($stmt, 1, "ipc", DB2_PARAM_IN);
$ret=db2_bind_param($stmt, 2, "ctl", DB2_PARAM_IN);
$ret=db2_bind_param($stmt, 3, "clobIn", DB2_PARAM_IN);
$ret=db2_bind_param($stmt, 4, "clobOut", DB2_PARAM_OUT);
$ret=db2_execute($stmt);
// var_dump($clobOut);
if (strpos($clobOut,"4444444444.44")>0) echo "success";
else echo "fail";
?>
Hint: If $clobIn PHP XML single quote / double quote issues are driving you nuts try the following technique.
BTW – For the enterprising do-it-yourself PHP builder you can see how very easy it would be to make a custom
call *PGM API with parameter substitution using str_replace() function similar to test_lib_replace(),
something like function ZZCALL($INCHARA,$INCHARB,$INDEC1,$INDEC2,$INDS1)
$xml = <<<ENDPROC
<?xml version='1.0'?>
<script>
<pgm name='ZZCALL' lib='xyzlibxmlservicexyz'>
<parm io='both'>
<data type='1A' var='INCHARA'>a</data>
</parm>
<parm io='both'>
<data type='1A' var='INCHARB'>b</data>
</parm>
<parm io='both'>
<data type='7p4' var='INDEC1'>11.1111</data>
</parm>
<parm io='both'>
<data type='12p2' var='INDEC2'>222.22</data>
</parm>
<parm io='both'>
<ds>
<data type='1A' var='INDS1.DSCHARA'>x</data>
<data type='1A' var='INDS1.DSCHARB'>y</data>
<data type='7p4' var='INDS1.DSDEC1'>66.6666</data>
<data type='12p2' var='INDS1.DSDEC2'>77777.77</data>
</ds>
</parm>
<return>
<data type='10i0'>0</data>
</return>
</pgm>
</script>
ENDPROC;
$clobIn = test_lib_replace($xml);
// xml common text replacement
function test_lib_replace($xml) {
global $libxmlservice, $iOPM;
if (!$iOPM) {
$was = array("xyzlibxmlservicexyz");
$now = array("$libxmlservice");
}
else {
$was = array("xyzlibxmlservicexyz","<pgm");
$now = array("$libxmlservice","<pgm mode='opm'");
}
$out = str_replace($was,$now,$xml);
return $out;
}
XMLSERVICE can be stopped …¶
Debug technique:¶
It’s as easy as 1-2-3-4-5-6-7-8-9-10 :)
- Add the following line to your PHP script before the program call to be debugged. $toolkitConn should be your toolkit connection object.
``$toolkitConn->setOptions(array('customControl'=>'*debug')).``
Run your script.
The script will "hang" while it waits on #2 below...
(move to green screen 5250 for steps 2-10)
- A MSGW inquiry message in DSPMSG QSYSOPR will be generated by the toolkit.
- Note the job information (number, name, user) provided in the MSGW.
- STRSRVJOB using that job information as parameters.
- STRDBG with the program and library you wish to debug.
- Answer the MSGW. Any answer will do–“G” is fine.
- The RPG program source will appear in debug mode in your terminal, ready to step through, allowing you to inspect variables, etc.
- When done inspecting and stepping, let the RPG program complete (using function keys indicated on screen).
- ENDDBG
- ENDSRVJOB