Debugging XA Calls in a JPA session running BMT with Netbeans 8.0.2

Overview

BMT calls          JDBC Driver calls 
ut.begin()         oracle.jdbc.xa.client.OracleXAResource   
... 
ut.commit()        oracle.jdbc.xa.client.OracleXAResource.end
                   oracle.jdbc.xa.client.OracleXAResource.commit  <--- Here we want to set a Breakpoint 

Prepare the Breakpoint

Class Name           : oracle.jdbc.xa.client.OracleXAResource
Method Name          : commit
Stop on              : Method Entry 
Actions - Suspend    : All Threads
  •  Select suspend all Threads if you want to avoid that any  Wildly Thread is running a rollback
  •  If you want Transaction Recovery takes place by other Wildfly Threads you may select Suspend Breakpoint Thread
  •  Don’t use  oracle.jdbc.xa.OracleXAResource for debugging as this package only defines abstract methods

Start the Netbeans project in DEBUG MODE

Netbeans Debug -> Debug Main Project 
--> Above action will redeploy our project in DEBUG mode

NetBeans: Deploying on WildFly Application Server
    profile mode: false
    debug mode: true
    force redeploy: true
  Undeploying ...
  Initial deploying WFJPA2EL to /usr/local/wildfly-8.2.0.Final/standalone/deployments/WFJPA2EL-1.0.war
  Completed initial distribution of WFJPA2EL
  Deploying /usr/local/wildfly-8.2.0.Final/standalone/deployments/WFJPA2EL-1.0.war
  Application Deployed

Debugger console reports successfully setting the breakpoint in [oracle.jdbc.xa.client.OracleXAResource].commit
  Attaching to localhost:8787
  MethodBreakpoint [oracle.jdbc.xa.client.OracleXAResource].commit successfully submitted.
  User program running

After the program hits a breakpoint runs Debugger Console should report 
Method breakpoint hit in oracle.jdbc.xa.client.OracleXAResource.commit at line 553 by thread default task-3.
Thread default task-3 stopped at OracleXAResource.java:553.

How to Copy the Stack Trace after our Worker Thread stops at a Breakpoint

Select Debugging TAB
  default task-7  [ this Thread was stopped by our Debugger ]
     Hidden Soruce Calls
       OracleXAResource.java:553   <-- Right Click here and select  COPY STACK
Stack Sample 
"default task-7"
oracle.jdbc.xa.client.OracleXAResource.commit(OracleXAResource.java:553)
org.jboss.jca.adapters.jdbc.xa.XAManagedConnection.commit(XAManagedConnection.java:338)
org.jboss.jca.core.tx.jbossts.XAResourceWrapperImpl.commit(XAResourceWrapperImpl.java:107)
com.arjuna.ats.internal.jta.resources.arjunacore.XAResourceRecord.topLevelOnePhaseCommit(XAResourceRecord.java:679)
com.arjuna.ats.arjuna.coordinator.BasicAction.onePhaseCommit(BasicAction.java:2317)
com.arjuna.ats.arjuna.coordinator.BasicAction.End(BasicAction.java:1475)
com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:96)
com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:162)
com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1166)
com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:126)
com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.commit(BaseTransactionManagerDelegate.java:75)
org.jboss.tm.usertx.client.ServerVMClientUserTransaction.commit(ServerVMClientUserTransaction.java:173)
com.hhu.wfjpa2el.JPATestBean.timeoutTest(JPATestBean.java:466)

JPA: Best practice to get and close EntityManagerFactory to avoid Unknown entity bean class error !

Problem Description

After redeploying a WebApplication using JPA you see the following error:

13:02:18.090 Unknown entity bean class: class com.hhu.wfjpa2el.Emp2, 
 please verify that this class has been marked with the @Entity annotation.

13:02:18.091 java.lang.IllegalArgumentException: Unknown entity bean class: class com.hhu.wfjpa2el.Emp2, 
  please verify that this class has been marked with the @Entity annotation.

Solution

  • Restart your WEBServer   or
  • Install a ServletContextListener and close the EMF during contextDestroyed() Event

JAVA Code for implementing a WebListener

package com.hhu.wfjpa2el;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import org.slf4j.LoggerFactory;

@WebListener
public class EMF implements ServletContextListener {

    private static EntityManagerFactory emf;
    final private static String pu = "jpaELPU";
    final static org.slf4j.Logger logger = LoggerFactory.getLogger(ServletContextListenerImpl.class);
    
    @Override
    public void contextInitialized(ServletContextEvent event) {
        logger.info("+++ ServletContextListener : contextInitialized - Inititalizing EMF for PU: " + pu);
        emf = Persistence.createEntityManagerFactory(pu);
        logger.info("+++ ServletContextListener : contextInitialized - Init EMF done for PU: " + pu);
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        logger.info("+++ ServletContextListener : contextDestroyed - Closing EMF for PU: " + pu);
        emf.close();
        logger.info("+++ ServletContextListener : contextDestroyed - Closed EMF done for PU " + pu);
    }

    public static EntityManager createEntityManager() {
        if (emf == null) {
            throw new IllegalStateException("Context is not initialized yet.");
        }
        return emf.createEntityManager();
    }
}

Initialize your Entity Manager by running :  em = EMF.createEntityManager();
Java Code: 
public static EntityManager getEntityManager() 
      {
        EntityManager em = threadLocal.get();
        if (em == null) 
          {
          // setRunTimeInfo(getRunTimeInfo() + Tools.add_hmtl_pre_tag("Creating Entity Manager ! "  ));
            if ( enableLogger )            
                logger.info("Creating Entity Manager Factory ..." );
            em = EMF.createEntityManager();
            threadLocal.set(em);
          }
        return em;
      }

Testing the Code wiht maven deploy/undeploy command

Deploy the WebApplication 
[oracle@wls1 WFJPA2EL]$  mvn wildfly:deploy

Wilfdly Log report:  
13:11:23,170 INFO  [stdout] (MSC service thread 1-4) 13:11:23 [MSC service thread 1-4] INFO  c.h.w.ServletContextListenerImpl - i
                   +++ ServletContextListener : contextInitialized - Init EMF done for PU: jpaELPU
13:11:23,173 INFO  [javax.enterprise.resource.webcontainer.jsf.config] (MSC service thread 1-4) Initializing Mojarra 2.2.8-jbossorg-1 20140822-1131 for context '/WFJPA2EL-1.0'
13:11:23,518 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-4) JBAS017534: Registered web context: /WFJPA2EL-1.0
13:11:24,010 INFO  [org.jboss.as.server] (management-handler-thread - 1) JBAS018559: Deployed "WFJPA2EL-1.0.war" (runtime-name : "WFJPA2EL-1.0.war")

Undeploy the WebApplication 
[oracle@wls1 WFJPA2EL]$   mvn wildfly:undeploy 

Wilfdly Log report:  
13:11:23,170 INFO  [stdout] (MSC service thread 1-4) 13:11:23 [MSC service thread 1-4] INFO  c.h.w.ServletContextListenerImpl - i
                    +++ ServletContextListener : contextInitialized - Init EMF done for PU: jpaELPU
13:11:23,173 INFO  [javax.enterprise.resource.webcontainer.jsf.config] (MSC service thread 1-4) Initializing Mojarra 2.2.8-jbossorg-1 20140822-1131 for context '/WFJPA2EL-1.0'
13:11:23,518 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-4) JBAS017534: Registered web context: /WFJPA2EL-1.0
13:11:24,010 INFO  [org.jboss.as.server] (management-handler-thread - 1) JBAS018559: Deployed "WFJPA2EL-1.0.war" (runtime-name : "WFJPA2EL-1.0.war")
13:13:02,751 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-7) JBAS017535: Unregistered web context: /WFJPA2EL-1.0

 

Reference

JavaScript Features: Ajax and JavaScript Timeout

What is AJAX?

  • AJAX = Asynchronous JavaScript and XML
  • AJAX is a technique for creating fast and dynamic web pages
  • AJAX allows web pages to be updated asynchronously by exchanging small amounts of data with the server behind the scenes
  • This means that it is possible to update parts of a web page, without reloading the whole page
  • Classic web pages, (which do not use AJAX) must reload the entire page if the content should change
  • Examples of applications using AJAX: Google Maps, Gmail, Youtube, and Facebook tabs
  • AJAX is based on Internet Standards, and uses a combination of:
    • XMLHttpRequest object (to exchange data asynchronously with a server)
    • JavaScript/DOM (to display/interact with the information)
    • CSS (to style the data)
    • XML (often used as the format for transferring data)

Ajax Request used in this sample application

  • Javascript code loadXMLDoc() to trigger an Ajax Request
function loadXMLDoc()
{
var xmlhttp;
var xmlf=document.getElementById('xmlf').value;
var txt,x,i;
if (window.XMLHttpRequest)
  {// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
  }
else
  {// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }

/*
 * Only a specific devision named "myDiv" of our HTTP page will be updated 
 */        
document.getElementById("myDiv").innerHTML="Inside loadXMLDOC -> XML File to load: " + xmlf;  

/*
 *  For details using onreadystatechange Event please read :  
 *  http://www.w3schools.com/ajax/ajax_xmlhttprequest_onreadystatechange.asp 
 */
xmlhttp.onreadystatechange=function()
  {     
  if (xmlhttp.readyState === 4 )
     {
        if ( xmlhttp.status === 200)
            {
            xmlDoc=xmlhttp.responseXML;
            txt="";
            x=xmlDoc.getElementsByTagName("ARTIST");
            for (i=0;i<x.length;i++)
                {
                txt=txt + x[i].childNodes[0].nodeValue + "<br>";
                }
            document.getElementById("myDiv").innerHTML=txt;
            }
         else
            {
            document.getElementById("myDiv").innerHTML='Error loading XML file: ' + xmlf + ' HTTP Status Code: ' + xmlhttp.status;            
            }
     }      
  };
xmlhttp.open("GET",xmlf,true);
xmlhttp.send();
}

Function Details:

  • The function loadXMLDoc() starts an asyncronous  Ajax request
  • Parameter xmls points to XM file cd.xml which gets loaded during this request
  • xmlhttp.open(“GET”,xmlf, true) means we use an HTTP GET request to load cd.xml. True means the load request is asyncronous.
  •  xmlhttp.send() actually sends the HTTP request
  •  xmlhttp.onreadystatechange function() gets invoked when HTTP response is ready
  • x=xmlDoc.getElementsByTagName(“ARTIST”) scans the XML document for ARTISTS attribute
  • txt=txt + x[i].childNodes[0].nodeValue + “<br>” adds the artists to our result string
  •  Finally   document.getElementById(“myDiv”).innerHTML=txt updates the only myDiv part of our WEB page
  •  In case of an error [ You may just change cd.xml to cdd.xml  for testing ]
      document.getElementById(“myDiv”).innerHTML=’Error loading XML file: ‘ + xmlf + ‘ HTTP Status Code: ‘ + xmlhttp.status;
      returns some error like:    Error loading XML file: cdd.xml HTTP Status Code: 404
  • For further details you may read following article :

Implementing a Page TimeOut using JavaScript

  • This is quite simple – For details please read function checkdelay() in JavaScript Code published below.
  • JavaScript Code :
JavaScript Code 
<!DOCTYPE html>
<html>
<head>
<script>
    
function redirect()
{
    window.location="https://google.de";
}

function redirecttohome()
{
    window.location="http://localhost:8180/JavaScriptandAjax-1.0/";
}

function redirectdelay()
{   
   actdelay = delay;
   checkdelay();
}
   
function checkdelay()
{
    /*
     * As long we don't reach the timeout value we need to reschedule checkdelay()
     * every second !
     */
    document.getElementById("myDiv").innerHTML="This page wil be redirected in " + actdelay + " seconds !"; 
    actdelay = actdelay - 1 ;
    if ( actdelay >= 0 )
        setTimeout('checkdelay()', 1000);
    else 
        redirecttohome();
}            


function clean()
{
   document.getElementById("myDiv").innerHTML="";    
}

function loadXMLDoc()
{
var xmlhttp;
var xmlf=document.getElementById('xmlf').value;
var txt,x,i;
if (window.XMLHttpRequest)
  {// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
  }
else
  {// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }

/*
 * Only a specific devision named "myDiv" of our HTTP page will be updated 
 */        
document.getElementById("myDiv").innerHTML="Inside loadXMLDOC -> XML File to load: " + xmlf;  

/*
 *  For details using onreadystatechange Event please read :  
 *  http://www.w3schools.com/ajax/ajax_xmlhttprequest_onreadystatechange.asp 
 */
xmlhttp.onreadystatechange=function()
  {     
  if (xmlhttp.readyState === 4 )
     {
        if ( xmlhttp.status === 200)
            {
            xmlDoc=xmlhttp.responseXML;
            txt="";
            x=xmlDoc.getElementsByTagName("ARTIST");
            for (i=0;i<x.length;i++)
                {
                txt=txt + x[i].childNodes[0].nodeValue + "<br>";
                }
            document.getElementById("myDiv").innerHTML=txt;
            }
         else
            {
            document.getElementById("myDiv").innerHTML='Error loading XML file: ' + xmlf + ' HTTP Status Code: ' + xmlhttp.status;            
            }
     }      
  };
xmlhttp.open("GET",xmlf,true);
xmlhttp.send();

}
    // global Javascript values 
var delay=10;
var actdeley;
</script>
</head>

<body>

<h2>My CD Collection:</h2>
<input name="XMLFile" type="text" maxlength="16" id="xmlf" value="cd.xml" />
<div id="myDiv"></div>
<button type="button" onclick="loadXMLDoc()">Get my CD collection</button>
<button type="button" onclick="clean()">Clean Display</button>
<button type="button" onclick="redirect()">Page Redirect to Google </button>
<button type="button" onclick="redirectdelay()">Delayed Page Redirect to our Home Page </button>
</body>
</html>

XML File used in this sample : cd.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<CATALOG>
    <CD>
        <TITLE>Empire Burlesque</TITLE>
        <ARTIST>Bob Dylan</ARTIST>
        <COUNTRY>USA</COUNTRY>
        <COMPANY>Columbia</COMPANY>
        <PRICE>10.90</PRICE>
        <YEAR>1985</YEAR>
    </CD>
    <CD>
        <TITLE>Hide your heart</TITLE>
        <ARTIST>Bonnie Tyler</ARTIST>
        <COUNTRY>UK</COUNTRY>
        <COMPANY>CBS Records</COMPANY>
        <PRICE>9.90</PRICE>
        <YEAR>1988</YEAR>
    </CD>
    <CD>
        <TITLE>Greatest Hits</TITLE>
        <ARTIST>Dolly Parton</ARTIST>
        <COUNTRY>USA</COUNTRY>
        <COMPANY>RCA</COMPANY>
        <PRICE>9.90</PRICE>
        <YEAR>1982</YEAR>
    </CD>
</CATALOG>

Reference

Most Info of this POST are just  copied from:

Using TM API to suspend and resume a JTA transaction to allow JDBC Commits

Assume your project has the following JPA transaction requirements

  • Start long a  running JTA transaction
  • Within the same thread which starts the JTA transaction you need to integrate a JAVA package which runs JDBC initiated COMMITs
  • The transaction outcome of this local transaction should be independent from our global JTA traansaction

Test Environment

12:09:59.294 Hibernate Version: 4.3.7.Final
12:09:59.294 Driver Name             : Oracle JDBC driver
12:09:59.294 Driver Version          : 12.1.0.2.0
12:09:59.294 Database Product Version: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
             With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
             Advanced Analytics and Real Application Testing options
12:10:01.448 DB Name:  BANKA
12:10:01.449 1. Instance Name: bankA_1 - Host: hract21.example.com - Pooled XA Connections: 34
12:10:01.449 2. Instance Name: bankA_3 - Host: hract22.example.com - Pooled XA Connections: 33

Call Flow using UserTransaction API [ not working ]

Global JPA transaction:
  ut  = (UserTransaction)new InitialContext().lookup("java:comp/UserTransaction");
  ut.begin();
  em=getEntityManager();
  em.joinTransaction();
  em.persist(e);
  em.flush();                                // Insert record into our RAC DB 
  em.merge(e);                               // Update new record

Start local transaction which is independent from global transaction !!
  Connection c1 = ds1.getConnection();
  preparedStmt.executeUpdate();
  c1.commit(); 
-> Local Commit fails with following error 
Error 
11:13:57.087 Error in writelog()
11:13:57.090 You cannot commit during a managed transaction!
11:13:57.091 java.sql.SQLException: You cannot commit during a managed transaction!
    at org.jboss.jca.adapters.jdbc.BaseWrapperManagedConnection.jdbcCommit(BaseWrapperManagedConnection.java:1065)
    at org.jboss.jca.adapters.jdbc.WrappedConnection.commit(WrappedConnection.java:758)
    at com.hhu.wfjpa2el.JPATestBean.writeLog(JPATestBean.java:1729)
    at com.hhu.wfjpa2el.JPATestBean.increaseSalary(JPATestBean.java:1221)
    at com.hhu.wfjpa2el.JPATestBean.testSuspend(JPATestBean.java:630)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

-> Your are not allowed to call commit() or rollback() when a JTA transaction is ACTIVE !

Fix : Use the JEE 6 introduced TM API and suspend/resume the JTA transaction

Call Flow
  tm = (TransactionManager)ctx.lookup("java:/TransactionManager"); 
  tm.setTransactionTimeout(txTimeout);
  tm.begin();
  em=getEntityManager();
  em.joinTransaction();
  em.persist(e);
  em.flush();                                // Insert record into our RAC DB 
  em.merge(e);                               // Update new record
  tx = tm.suspend();                         // Save the transaction handle - we need to resume the transaction again
-> Global Transaction is suspended now

Start local transaction which is independent from global transaction !!
  Connection c1 = ds1.getConnection();
  c1.setAutoCommit(false);
  preparedStmt.executeUpdate();
  c1.commit();
-> Local Transaction is commited 

Resume global JTA transaction
 tm.resume(tx);
 em.merge(e);
 tm.commit();
-> Global JTA transaction is now commited 

Working Log

 
2:14:31.826 Calling increaseSalary() in progress - ID: 9997 - isUseSuspend : true
12:14:31.826  ------- Testing Suspend/Resume Operation ----------
12:14:31.826 Lookup Transactionmanager: ctx.lookup(java:/TransactionManager) - Tx Timeout: 120
12:14:31.827 Begin Transaction: tm.begin() - Before [TM status:  6 - STATUS_NO_TRANSACTION] - After [TM status:  0 - STATUS_ACTIVE]
12:14:41.569 checkEntity() -  :  empno: 1000001 - Record not yet found in Database !
12:14:41.569 :: After First Salary Change - Old Sal : 1000 - Salary Increase I : 500 - Current Salary: 1500
12:14:41.570 Suspended Transaction: tm.suspend() - Before [TM status:  0 - STATUS_ACTIVE] - After [TM status:  6 - STATUS_NO_TRANSACTION]
12:14:41.570 writelog():: Message: 12:14:41.570 :: After First Salary Change - Old Sal : 1000 - Salary Increase I : 500 - Current Salary: 1500 - ENO: 1000001
12:14:41.624 Leaving writelog() without Exceptions - Data commited !
12:14:41.624 Resumed Transaction: tm.resume(transaction)  - Before [TM status:  6 - STATUS_NO_TRANSACTION] - After [TM status:  0 - STATUS_ACTIVE]
12:14:41.692 :: Commit Tx: tm.commit() done   - Before [TM status:  0 - STATUS_ACTIVE] - After [TM status:  6 - STATUS_NO_TRANSACTION]
12:14:41.692 writelog():: Message: 12:14:41.692 :: 2nd Salary Change - Old Sal : 1000 - Salary Increase II : 99 - Current Salary: 1599 Need to Rollback : false - ENO: 1000001
12:14:41.779 Leaving writelog() without Exceptions - Data commited !
12:14:41.780 writelog():: Message: 12:14:41.780 :: Commit Tx: tm.commit() done   - Before [TM status:  0 - STATUS_ACTIVE] - After [TM status:  6 - STATUS_NO_TRANSACTION] - ENO: 1000001
12:14:41.801 Leaving writelog() without Exceptions - Data commited !
12:14:41.801  ------- Clear an reread Entity after TX completion  ----------
12:14:41.848 checkEntity() -  :  empno: 1000001 - Sal: 1599 - Entity Salary Persistence : 1599 - Managed Entity Status : true - STALE Data: false
12:14:41.940 -->readLog(): [empno=1000001] - Found 3 Records
12:14:41.940            : LogID:     20 - 12:14:41.570 :: After First Salary Change - Old Sal : 1000 - Salary Increase I : 500 - Current Salary: 1500 
12:14:41.940            : LogID:     21 - 12:14:41.692 :: 2nd Salary Change - Old Sal : 1000 - Salary Increase II : 99 - Current Salary: 1599 Need to Rollback : false 
12:14:41.940            : LogID:     22 - 12:14:41.780 :: Commit Tx: tm.commit() done   - Before [TM status:  0 - STATUS_ACTIVE] - After [TM status:  6 - STATUS_NO_TRANSACTION] 
12:14:41.940 Leaving increaseSalary() without Exceptions !
12:14:41.940 Leaving increaseSalary() - Entity manager  closed !

RAC performance Tuning with JMeter and AWR

Tuning Steps

  • Run AWR to figure out any RAC specific performance problems   
  • Change your application / Change schema objects
  • Verify performance gains with Jmeter
  • Repeat step 1 to step 3

 

Review current Performance status by using AWR

Reviewing SQL performance and Cluster Wait Time 
SQL ordered by CPU Time (Global)
    Captured SQL account for 54.4% of Total CPU Time (s): 235
    Captured PL/SQL account for 1.0% of Total CPU Time (s): 235
     Total     Per Execution     Percentage of Total      
SQL Id         CPU (s)   Elapsed (s) IOWait (s)   Gets   Reads    Rows    Cluster(s)    Execs   DB CPU  DB time  IO Wait    Gets    Read  Cluster    Execs      SQL Text
5m84n5c8k0k4c    49.37    3,317.61    6.99     319,368    792    30,000    2,023.00    30,000     21.04   41.29     1.80    5.83    2.99    57.73      8.07     Insert into logemp2 values (se...
a1h541jgwjdsj    25.56      533.35    6.66   3,566,809    285    30,000      459.23    10,000     10.89    6.64     1.71   65.06    1.08    13.11      2.69     select logemp2x0_.LOGID as LOG...
1aa2fpqtx557g    11.53       43.59    0.06      94,906     37    30,034       17.74    30,034      4.92    0.54     0.02    1.73    0.14     0.51      8.08     update seq$ set increment$=:2,...
8fv480az2kx9h     7.15      568.46    0.12      34,968     11    17,377      556.21    17,377      3.05    7.08     0.03    0.64    0.04    15.87      4.68     select increment$, minvalue, m...
anxm5vn9kxahy     5.91      289.35    1.71      57,697    151    10,000      266.43    10,000      2.15    1.77     0.08    0.68    0.01     3.77      2.69     select emp2x0_.EMPNO as EMPNO1...
8nrq20tnp5wvx     3.03      75.80      0.83      40,162     22    10,000       68.54    10,000     1.29    0.94     0.21    0.73    0.08     1.96      2.69     update EMP2 set ENAME=:1 , JOB...

Top DB Objects
    Top DB Objects by DB Time with respect to Application, Cluster, User I/O, buffer busy waits and In-Memory DB events only.
    Tablespace name is not available for reports generated from the root PDB of a consolidated database.
Object ID    % Activity    Event                    % Event     Object Name (Type)          Tablespace
99421        11.28         gc current block busy     6.05       SCOTT.LOGEMP2_PK (INDEX)    USERS
                           gc buffer busy release    3.11     
                           gc buffer busy acquire    2.04     
99419          4.82        gc buffer busy acquire    2.04       SCOTT.EMP2_PK (INDEX)       USERS
                           gc cr block busy          1.80     
99420          4.42        gc cr block busy          2.78       SCOTT.LOGEMP2 (TABLE)       USERS

-> Insert into log table logemp2 takes much DB CPU time and also consumers very high cluster Wait time 
   We insert 3x more records into our log table ( 30.000 ) compared the record count for table EMP2 ( 10.000 )

-> Waits for Primay Key SCOTT.LOGEMP2_PK seems to be the major Wait Event and needs to be tuned first 

Review and change/modify DB objects responsible for Logging

Current Object Creation scripts :  
create table logemp2 ( LOGID number, EMPNO number(22),  message varchar(300) );
alter table logemp2 add CONSTRAINT  logemp2_pk  PRIMARY KEY (logid);
desc logemp2;

drop sequence SEQ_LOGEMP2;
create sequence SEQ_LOGEMP2  minvalue 1 maxvalue 9999999999999999999999999999
  start with 1 increment by 1 NOCACHE ORDER;
  
-> First tuning suggestions:  
   Drop Primary Key for table Logemp2  andcreate sequence with CACHE Noorder 
  
New Object creation script :
create table logemp2 ( LOGID number, EMPNO number(22),  message varchar(300) );
desc logemp2;
drop sequence SEQ_LOGEMP2;
create sequence SEQ_LOGEMP2  minvalue 1 maxvalue 9999999999999999999999999999
  start with 1 increment by 1 cache 1000 noorder;    

Rerun JMETER tests and compare results

  • Jmeter Thread Group Configurtion : 10 Threads / Loop Count: 1000
  • Initial Jmeter test results

AWR1

  • Jmeter test results after applying above DDL changes

AWR2

  • This simple change increase the RAC performance by 50 %  . Not bad for 10  minutes tuning

 

Further Tuning steps

  • Lets have a look at the next tuning steps by reviewing AWR
 
Top Events
    Top Events by DB Time
    % Activity is the percentage of DB Time due to the event
Event                       Event Class   Session Type   % Activity  Avg Active Sessions
log file sync               Commit        FOREGROUND      35.32            3.20
log file parallel write     System I/O    BACKGROUND      15.39            1.39
gc buffer busy acquire      Cluster       FOREGROUND       9.06            0.82
gcs log flush sync          Other         BACKGROUND       8.67            0.78
gc cr block busy            Cluster       FOREGROUND      8.15             0.74

-> Using faster REDO LOGS and reduce the number COMMIT may be the next step of tuning

 

Reference

JMeter first steps for solving/verifying a RAC performance problem

What is JMeter ?

  • Jmeter is a s functional testing tool for a web application, file server, web server and even database
  • Is easy to configure and provides all needed tools to run HTTP load tests against any WebServer

Download and Install JMeter

Download Jmeter 2.13 from  http://jmeter.apache.org/download_jmeter.cgin
 $ mkdir JMETER
 $ unzip apache-jmeter-2.13.zip
 $ pwd
     /home/oracle/JMETER/apache-jmeter-2.13/bin
 $ chmod 755 jmeter
 $ jmeter
--> GUI should be started !

 

First JMeter Project

Add Users
Edit > Threads(User) -> Thread Group

Add HTTP Request
Thread Group [ RC ] -> Add -> Sampler -> HTTP request
 Server Name : localhost   
 Port Number : 8180   
 Path        : /WFJPA2EL-1.0

Add Listener to display HTTP traffic
Thread Group [ RC ] -> Add -> Listener -> View Results Tree

Now Press Start and verify the HTTP traffic
View Result Tree -> Traffic -> Click on a Single HTTP request
There a 3 Viewing Options to display the test results 
 - Sampler results 
 - Request
 - Response data  

Details on above Viewing Option
- Sampler Results 
  Thread Name: Thread Group 1-1
  Sample Start: 2015-06-09 08:30:58 CEST
  Load time: 29
  Connect Time: 4
  Latency: 6
  Size in bytes: 4910
  Headers size in bytes: 454
  Body size in bytes: 4456
  Sample Count: 1
  Error Count: 0
  Response code: 200
  Response message: OK

  Response headers:
   HTTP/1.1 200 OK
   Connection: keep-alive
   X-Powered-By: Undertow/1
   Set-Cookie: JSESSIONID=6RuYgEBp_dbe0VnE2S_8FWk2.wls1; path=/WFJPA2EL-1.0
   Server: WildFly/8
   Content-Type: text/html;charset=UTF-8
   Content-Length: 4456
   Date: Tue, 09 Jun 2015 06:30:58 GMT

  HTTPSampleResult fields:
   ContentType: text/html;charset=UTF-8
   DataEncoding: UTF-8

- Request data
  GET http://localhost:8180/WFJPA2EL-1.0/
  [no cookies]
  Request Headers:
  Connection: keep-alive
  Host: localhost:8180
  User-Agent: Apache-HttpClient/4.2.6 (java 1.5)
  Thread Group [ RC ] -> Add -> Sampler -> HTTP request

- Response Data [ The HTML document ! ]
  <?xml version='1.0' encoding='UTF-8' ?>
  <!DOCTYPE html>
  <html xmlns="http://www.w3.org/1999/xhtml"><head id="j_idt2">
        <title>Testing RAC - J2EE JPA2 API! </title>
        <style> 
         .BGImage{ background-image: url("resources/images/1920x1200_night.png"); }
        </style></head><body class="BGImage"><table>
   <tbody>
   <tr>
   ...

Add HTTP Cookie Manager and HTTP Cache Manager

Thread Group [ RC ] -> Add -> Config Element -> HTTP Cookie Manager 
Thread Group [ RC ] -> Add -> Config Element -> HTTP Cache Manager 
HTTP Cache Manager  -> simulates WEB Browser Caching
HTTP Cookie Manager -> simulates Browser Cookie 
 -> Click on HTTP cookie manager -> Uncheck Clear Coookies  each Iteration
  
With an enable HTTP Cookie Manager the request should look like  
  GET http://localhost:8180/WFJPA2EL-1.0/
  Cookie Data:
  JSESSIONID=dIV4Kg4Ge1672IoaR75GPWcW.wls1
Without an HTTP Cookie Manager the Request looks like: 
  GET http://localhost:8180/WFJPA2EL-1.0/
  [no cookies]

Recording a User Script With a Browser

For inital testing modify Thread Group : 
  Number of Threads ( user ) : 1
  Loop Count                 : 1

Use the Recording template 
File -> Templates -> Recording 
This creates a Test Plan with following major elements
 - User Defined Variables
 - HTTP Request Defaults
 - HTTP Cookie Manager
 - Thread Group
   - Recording Controller
   - View Results Tree
 - WorkBench
   - HTTP(S) Test Script Recorder   
   - View Results Tree  

Verify HTTP(S) Test Script Recorder settings  and start the Recorder 
--> Global Settings for Proxy Port :  8888
    Go to the end of HTTP(S) Test Script Recorder Page and press  << Start >>

Prepare your WEBapplication by modify the Firefox Proxy Configuration
Edit -> Preferences -> Advanced -> Network -> Settings -> Manuals Proxy Configuration 
  HTTP Proxy : localhost  Port : 8888 
  Remove Entries NO PROXY entries like  : localhost, 127.0.0.1

Record the Session 
Start the initial HTTP GET request
$ firefox http://localhost:8180/WFJPA2EL-1.0/  
Now Press your GUI buttons  to create the HTTP Post requests !

Review Recorded HTTP traffic under 
Thread Group -> Recording Controller ->
   45 /WFJPA2EL-1.0
   45 /WFJPA2EL-1.0                    GET 
   46 /WFJPA2EL-1.0/                   GET
   47 /WFJPA2EL-1.0/faces/index.xhtml  POST
   48 /WFJPA2EL-1.0/faces/index.xhtml  POST
   49 /WFJPA2EL-1.0/faces/index.xhtml  POST
   50 /WFJPA2EL-1.0/faces/index.xhtml  POST
   51 /WFJPA2EL-1.0/faces/index.xhtml  GET

Now Replay the Recorded Session by pressing START and check the  newly filled View Results Tree
-> All POST request are failing with 
   Error Count: 1
   Response code: 500
   Response message: Internal Server Error

The HTTP GET request returns 
   j_id1:javax.faces.ViewState:0" value="-3761271259220317840:-5309836328462799600" 

Jmeter-ViewStatePict1        


wheras the POST request sending back the old recorded ViewState variable   
  javax.faces.ViewState=-4902608378562698912%3A-4211783223364451074

Jmeter-ViewStatePict2


As you can see the ViewState variable returned from the HTTP GET request is different than the 
ViewState variable sent in the subsequent HTTP POST request. This is the root cause for getting 
Response code: 500 errors 

Fix :
We need to extract the ViewState from the first GET request into a variable and 
arm our subsequent HTTP POST with that variable .


Step 1: Extract the hidden Field ViewState into a Variable 
First Add a Debug Sampler 
Thread Group -> Add -> Sampler -> Debug Sampler 

Locate the ViewState value returned from the first HTTP GET request
Thread Group -> View  Result Tree [ Use the same HTTP requst ID as found in the Recording Controller output
View Result Tree     :  45 /WFJPA2EL-1.0/
Recording Controller :  45 /WFJPA2EL-1.0/

Copy  from View Result Tree ( Use <ctrl>C and <ctrl>V  for copy and paste ) the following Line :
"j_id1:javax.faces.ViewState:0" value="-4364374341049834252:-7433662177008040460" autocomplete="off"

Add regular Expression to extrace ViewState variable - 
Go the first HTTP GET request [ request 31 ]  
  Recording Controller ->  RC HTTP GET request -> Add -> Post Processors -> Regular Expression Extractor 

Reference Name     : jsfViewState 
Regular Expression : input type="hidden" name="javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="(.+?)" autocomplete
Template           : $1$
Default Value      : DEFAULT-VALUE-NOT-EXPECTED

Note we changed  in the Regular Expression Extractor :
  ViewState:0" value="-4364374341049834252:-7433662177008040460" 
to
  ViewState:0" value="(.+?)"

Jmeter-ViewStatePict3


Now Replay and verify that Debug Sampler successfully extract the jsfViewState parameter 
View Result Tree -> Debug Sampler ->  Response Data 
JMeterVariables:
..
jsfViewState=8326703641583194307:-77748042595564357
jsfViewState_g=1
jsfViewState_g0=input type="hidden" name="javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="8326703641583194307:-77748042595564357" autocomplete
jsfViewState_g1=8326703641583194307:-7774804259556435
-> jsfViewState variable is succesfully extracted  from the HTTP GET request 

Step 2 : Replace all related POST request replace the ViewState Parameter with our  extracted  ${jsfViewState}  Variable 
Goto Recording Controller click on the first POST Request wich is in our case : 32 /WFJPA2EL-1.0/faces/index.xhtml
Scroll Down the Parameter Box and locate 
javax.faces.ViewState    7488737670588160729:2714299608714531806    true    true 
Replace the value field 7488737670588160729:2714299608714531806    with our view state variable : ${jsfViewState}  
The complete record should now look like ; 

Jmeter-ViewStatePict4

-> Note be careful and remove any spaces behind ${jsfViewState}     declaration 
  
Repeat this step for all subsequent HTTP POST requests .
Rerun the recorded session - all HTTP operation should be flagged green  

Jmeter-ViewStatePict5

The last HTTP GET request reports in the Sampler Box : 
Thread Name: Thread Group 1-1
Sample Start: 2015-06-18 19:42:35 CEST
Load time: 153
Connect Time: 0
Latency: 136
Size in bytes: 54033
Headers size in bytes: 0
Body size in bytes: 0
Sample Count: 1
Error Count: 0
Response code: 200
Response message: Number of samples in transaction : 5, number of failing samples : 0

Working with Assertions

 
Duration  Assertion
First lets have a look as the current statistics for out HTTP Post request by looking on out Summary Report  
                                      Samples  Avg     Min      Max   Std. DEv Error   Throughput       KB/s       
16 /WFJPA2EL-1.0/faces/index.xhtml    3    17    12    28    7.318    0.0        18.98    96.11     
-> We don't have any errors and the Average Response Time is 12 ms 

Rerun test again and check  Summary Report  
Add a Duration Assertion for the above HTTP Post with : 12 ms 
                                      Samples  Avg     Min      Max   Std. DEv Error          
176 /WFJPA2EL-1.0/faces/index.xhtml    15    13    11    28    4.02    0.066
-> 6,6 % of our requests shown some ERRORS 

View Test Results
Double click on the red marked Request 
  Assertion error: false
  Assertion failure: true
  Assertion failure message: The operation lasted too long: It took 13 milliseconds, but should not have lasted longer than 12 milliseconds.
-> Here we get Details about our failed Request

Add a response Assertion to a HTTP POST 
Recording Controller -> RC HTTP POST -> Add Assertions -> Response Assertion 

Jmeter-ViewStatePict6

In this HTTP response we expect to find following test pattern :
   -> Suspend Transaction - Status: SUSPEND - Salary:1500

Reviewing a failed Response Assertion :

JMeter-ViewStatePict7

 

First Performance Tests

For last testing we are  heavy business transaction doing the following :
- HTTP Request1      : Request the inital page via HTTP GET request
- HTTP POST Request2: Uses  a HTTP post request to
   - Start a JTA transaction ( Not JTA transaction are always XA transactuons
   - Run JPA flush [ == Insert a new db record ]
   - Suspend the JTA transaction using the JEE TransactionManager API
   - Add JTA transaction object, Entity Manager object to our HTTPSession Object
- HTTP POST Request3: Uses  a HTTP post request to
  - retrieve JTA transaction object and Entity Manager object from our HTTPSession Object
  - Resume the Transaction and update the record
  - Commit the record -  in case of any errors rollback the transacton
  - Cleanup HTTP session object , clear the Entity Manager
- HTTP Request4: Uses  a HTTP post request to
- Invalidate the HTTP session

For performance  testing we modify  our Thread Group :
Number of Threads ( user ) : 5
Loop Count                 : 1000
This JMETER session will run 5.000 Business Transactions
Note: Disable all Listeners for Throughput / Performance Testing as listeners are very CPU and
     Memory intensive .
-> For the inital performance test we will run only using the Summary report

Jmeter-Tune1

Findings :
- We are running 5.000 Transactions with a throughtput of 200 HTTP request per second
- About 0.18 % of our HTTP requests are failing
- The average duration of our HTTP post are between 30  and 59 ms

As we get some errors we will add the  View Results Tree.
Because we are in a testing phase where we print errors and runtine information to the User 
screen the HTML will give us an easy way to get details about the error

Jmeter-Tune2

Some Deatails about Listeners

Useful Listeners
  - Summary Report
  - Repsonse Time Graph
  - View Results in Table
  - View Results Tree

Note Disable all Listeners for Throughput / Performance Testing as listeners
are very CPU and Memory  time intensive

Real Testing with RAC, JMeter and Virtaulbox

Test-Configuration    
14:23:21.294 Calling  getRacInfo() in progress ... 
14:23:21.294 Hibernate Version: 4.3.7.Final
14:23:21.294 Driver Name             : Oracle JDBC driver
14:23:21.294 Driver Version          : 12.1.0.2.0
14:23:21.294 Database Product Version: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
             With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
             Advanced Analytics and Real Application Testing options
14:23:21.512 DB Name:  BANKA
14:23:21.512 1. Instance Name: bankA_3 - Host: hract21.example.com - Pooled XA Connections: 32
14:23:21.513 2. Instance Name: bankA_1 - Host: hract22.example.com - Pooled XA Connections: 31
14:23:21.513 Leaving getRacInfo() without Exceptions !

All tests run on a single s

Test Scenario
- 10 Threads running a complex Transaction using suspend and resume 1000x
- This translates to running 50.000 Transactions.
 
Testcase Details
 - Using 2 datasources having MAX Connections set to 50  
     Datasource 1 is a JPA datasource and is used to operate on our JPA Entities
     Datasource 2 simulates a Normal datasource [ used as a tracking tool ]
 - Even we need to rollback our global transaction we need to write some log information before the ROLLBACK 
 - The HTTP mentioned mentioned below are resp 
 - HTTP POST request 1 : adds an Entity to the HTTP session object
 - HTTP POST request 2 : Starts the transaction running tm.begin()
                         Calls em.flush() to store that record in our RAC DB asap
                         Supspend the XA Transaction running tm.suspend()
                         Logs some data via JDBC API and COMMITs that data [ this is possible as we have suspended our XA transaction ]
                         Resume the transaction using tm.resume()
                         Update our record running em.merge()
                         Commit the data running tm.commit()
                         Logs some data via JDBC API and COMMITs that data


Configuration and Test details 
Host System: 
 - Windows 8.1 
 - CPU i7-4710-HQ 2,5 GHz - 1 socket, 4 Physical CPus, 8 Logical CPUs - 16 Gbyte RAM 
Testcase 
  - VirtualBox System I   running : OEL 6.6, Wildfly 8.2 , 10 Threads ( running Jmeter )
  - VirtualBox System II  running : OEL 6.6, Oracle RAC 12.1.0.2.0 , Instance bankA1 
  - VirtualBox System III running : OEL 6.6, Oracle RAC 12.1.0.2.0 , Instance bankA2 
  - All VirtualBox System are configured to occupy a single physical CPU only 

What we exe expecting: 
- The testcase is CPU bound (  very little DB actions) 
- Our Host system running the Jmeter Threads should occupy  about 100 % of our CPU.

Single  Core Testing - Verifiy CPU details on our JMeter VBox System 

Guest System [ OEL 6.6 ] details :
[oracle@wls1 Desktop]$ nproc
1
[oracle@wls1 Desktop]$ lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                1
On-line CPU(s) list:   0
Thread(s) per core:    1
Core(s) per socket:    1
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 60
Stepping:              3
CPU MHz:               2496.669
BogoMIPS:              4993.33
L1d cache:             32K
L1d cache:             32K
L2d cache:             6144K
NUMA node0 CPU(s):     0

-> Only a Single Physical CPU is active for our Virtualbox System running 
the Jmeter tests !

Jmeter test results :
Jmeter_perfS

TaskManager Test results :
TaskManagerS

Resource Manager test results:
ResourceManagerS
Test Summary:
 - No all CPU ticks available are used for our testing 
 - This leads to a low TPS rate of 19.5 annd is far away from a real stress test

Assumption : We assume that the VirtualBox System running the JMeter threads is limiting factor !

-> Let's add  additonal CPU Power to the Virtualbos System 

Change VBox Configuration  to use all 4 physical CPUs: 
JMeter_4CPU_Setup
            

Verify transaction rate using JMeter Output: 
Jmeter_perfM

Verify CPU Usage via Task Manager : 
TaskManagerM

Test Summary after changing Virtualbox Setup to  use all phy. CPUs
- Transaction rate increased from 19,6 TPS to 51,5 TPS
- All CPUs are running at 100 % speed 

Reference :

Real Performance Testing with VirtualBox, Jmeter, Wildfly and Oracle RAC 12.1

Configuration and Test details

Host System 
 - Windows 8.1 
 - CPU i7-4710-HQ 2,5 GHz - 1 socket, 4 Physical CPus, 8 Logical CPUs - 16 Gbyte RAM 

Testcase 
  - VirtualBox System I   running : OEL 6.6, Wildfly 8.2 , 50 Threads ( using Jmeter )
  - VirtualBox System II  running : OEL 6.6, Oracle RAC 12.1.0.2.0 , running Instance bankA1 
  - VirtualBox System III running : OEL 6.6, Oracle RAC 12.1.0.2.0 , running Instance bankA2 


What we exe expecting 
- As the testcase is CPU bound (  very little DB actions) we expect a Host CPU utilization of 100 % .

Single  Core Testing – Using only a single physical CPUs

Guest System  VirtualBox System I [ OEL 6.6 ] CPU details :
[oracle@wls1 Desktop]$ nproc
1
  
[oracle@wls1 Desktop]$ lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                1
On-line CPU(s) list:   0
Thread(s) per core:    1
Core(s) per socket:    1
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 60
Stepping:              3
CPU MHz:               2496.669
BogoMIPS:              4993.33
L1d cache:             32K
L1d cache:             32K
L2d cache:             6144K
NUMA node0 CPU(s):     0

-> Only a Single CPU is active for our OEL 6.6 guest system!

TaskManager Output :
TaskManagerS
-> Complete CPU utiliztion is only 40 %

Resource Manager Output: 
ResourceManagerS
-> VirtualBox processes are multi-threaded [ this should be helpful for mulitple Testing ]

JMeter Output :
Jmeter_perfS
-> The Single CPU test is able to run at a rate of 20 TPS

 Single CPU Test Summary:

  • Single CPU test utilizes  only 40 % of our Host CPU
  • VirtualBox processes are using up to 50 threads
  • The current test system runs a rate of 20 TPS
  • If we can make happen a CPU utilization of 100 % we should see a rate of 50 TPS

Multiple Cores Testing – Using all 4 physical CPUs

Guest VirtualBox SystemI  [ OEL 6.6 ] details :
[oracle@wls1 Desktop]$ nproc
4
[oracle@wls1 Desktop]$  lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                4
On-line CPU(s) list:   0-3
Thread(s) per core:    1
Core(s) per socket:    4
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 60
Stepping:              3
CPU MHz:               2494.114
BogoMIPS:              4988.22
L1d cache:             32K
L1d cache:             32K
L2d cache:             6144K
NUMA node0 CPU(s):     0-3
 
--> All 4 physical processors are available at our Guest OS 

Test results :

Task Manager Output :

TaskManagerM
-> All 8 virtual CPUs are running at 100 % utilization 

JMeter Output: 

Jmeter_perfM
-> The whole System runs now at 50 TPS 

4-CPU Test Summary 

  • Using all CPUs increase the the TPS rate to over 51 TPS
  • For Performance Testing using configuring  Virtualbox to use  all  physical CPUs may be a good advice.
  • In the above test the VirtualBox systems running  the RAC instances only uses a single phy. CPU.
  • Our Virtualbox RAC system are not yet CPU bound and a single phy. CPU is sufficient
  • As we expected we can increase the TPS rate by factor 2.5 when we increase the initial HOST CPU utilization from 40 % to 100 %

Reference

Connection timeout message when running nslookup against GNS SCAN Address

Nslookup Error
[root@ns1 named]#  nslookup grac4-scan.grid4.example.com
;; connection timed out; trying next origin
Server:        192.168.5.50
Address:    192.168.5.50#53
** server can't find grac4-scan.grid4.example.com: NXDOMAIN

/var/log/messages of the BIND Nameserver  contains  a lot of IPV6 related errors 
  using GNS host : GNSTESTHOST 
..
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/AAAA/IN': 202.12.27.33#53
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/A/IN': 2001:503:ba3e::2:30#53
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/AAAA/IN': 2001:503:ba3e::2:30#53
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/A/IN': 2001:500:2::c#53
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/AAAA/IN': 2001:500:2::c#53
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/A/IN': 2001:500:2d::d#53
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/AAAA/IN': 2001:500:2d::d#53
....
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/A/IN': 2001:dc3::35#53
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/AAAA/IN': 2001:dc3::35#53
Jun 24 15:19:18 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/A/IN': 2001:502:f3ff::64#53

-> All the failed IVPV6 requests add a delay for the request and leads to the nslookup Timeout
-> As our network can't handle IPV6 we need to disable IVP6. 

FIX : Disable ipv6 on CentOS 6/7 / RHEL 6/7 

Edit the /etc/sysctl.conf.
# vi /etc/sysctl.conf
Put the following entry to disable IPv6 for all adapter.
net.ipv6.conf.all.disable_ipv6 = 1

[root@ns1 named]#  ifconfig eth1
eth1      Link encap:Ethernet  HWaddr 08:00:27:2B:5E:DD
          inet addr:192.168.5.50  Bcast:192.168.5.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2171 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1461 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:159819 (156.0 KiB)  TX bytes:185391 (181.0 KiB)
-> No IPV6 reference anymore 

After disabling IPV6 only very less named records should be logged in /var/log/messages : 
Jun 24 15:49:07 ns1 named[3152]: zone 2.168.192.in-addr.arpa/IN: sending notifies (serial 2009011201)
Jun 24 15:49:07 ns1 named[3152]: zone 5.168.192.in-addr.arpa/IN: sending notifies (serial 2009011201)
Jun 24 15:50:45 ns1 named[3152]: error (FORMERR) resolving 'GNSTESTHOST.grid4.example.com/AAAA/IN': 192.168.5.54#53
Jun 24 16:00:48 ns1 named[3152]: error (FORMERR) resolving 'GNSTESTHOST.grid4.example.com/AAAA/IN': 192.168.5.54#53
Jun 24 16:10:50 ns1 named[3152]: error (FORMERR) resolving 'GNSTESTHOST.grid4.example.com/AAAA/IN': 192.168.5.54#53
Jun 24 16:16:52 ns1 named[3152]: client 192.168.5.101#29873: RFC 1918 response from Internet for 5.1.168.192.in-addr.arpa
...

Nslookup should now  work fine 
[root@ns1 log]#  nslookup grac4-scan.grid4.example.com
Server:        192.168.5.50
Address:    192.168.5.50#53

Non-authoritative answer:
Name:    grac4-scan.grid4.example.com
Address: 192.168.5.200
Name:    grac4-scan.grid4.example.com
Address: 192.168.5.165
Name:    grac4-scan.grid4.example.com
Address: 192.168.5.166

How to fix a RAC database startup problem with orachk in 5 minutes ?

New TFA Collector bundles ORAchk and other RAC tools

TFA Collector Features

Installation of TFA Lite /  ORACHK

Note orachk is now bundled with TFA collector  
Use the MOS article below to download TFA collector 
    TFA Collector - Tool for Enhanced Diagnostic Gathering (Doc ID 1513912.2)

Extract and install orachk as root user 
root@grac41 t]# ls
installTFALite  TFACollectorDocV121250.pdf  TFALite_121250.zip
[root@grac41 t]# ./installTFALite
Starting TFA installation
Enter a location for installing TFA (/tfa will be appended if not supplied) [/home/oracle/t/tfa]: 
/home/oracle/TFA
...
---------------------------------.
|            TFA Users            |
+-----------+-----------+---------+
| User Name | User Type | Status  |
+-----------+-----------+---------+
| asmadmin  | GROUP     | Allowed |
| grid      | USER      | Allowed |
| oinstall  | GROUP     | Allowed |
| oracle    | USER      | Allowed |
'-----------+-----------+---------'
Summary of TFA Installation:
.------------------------------------------------------------.
|                           grac41                           |
+---------------------+--------------------------------------+
| Parameter           | Value                                |
+---------------------+--------------------------------------+
| Install location    | /home/oracle/TFA/tfa/grac41/tfa_home |
| Repository location | /home/oracle/TFA/tfa/repository      |
| Repository usage    | 0 MB out of 2982 MB                  |
'---------------------+--------------------------------------'
.------------------------------------------------------------.
|                           grac42                           |
+---------------------+--------------------------------------+
| Parameter           | Value                                |
+---------------------+--------------------------------------+
| Install location    | /home/oracle/TFA/tfa/grac42/tfa_home |
| Repository location | /home/oracle/TFA/tfa/repository      |
| Repository usage    | 0 MB out of 2982 MB                  |
'---------------------+--------------------------------------'
.------------------------------------------------------------.
|                           grac43                           |
+---------------------+--------------------------------------+
| Parameter           | Value                                |
+---------------------+--------------------------------------+
| Install location    | /home/oracle/TFA/tfa/grac43/tfa_home |
| Repository location | /home/oracle/TFA/tfa/repository      |
| Repository usage    | 0 MB out of 2982 MB                  |
'---------------------+--------------------------------------'
TFA is successfully installed...

 

Problem description

 
Either starting RAC instance with sqlplus or srvctl fails with errors :  

[oracle@grac43 dbs]$  sqlplus / as sysdba
SQL*Plus: Release 11.2.0.4.0 Production on Tue Jun 23 13:01:15 2015
Copyright (c) 1982, 2013, Oracle.  All rights reserved.
Connected to an idle instance.
SQL>  startup nomount
ORA-01078: failure in processing system parameters
ORA-01565: error in identifying file '+DATA/grac4/spfilegrac4.ora'
ORA-17503: ksfdopn:2 Failed to open file +DATA/grac4/spfilegrac4.ora
ORA-01034: ORACLE not available
ORA-27123: unable to attach to shared memory segment
Linux-x86_64 Error: 13: Permission denied
Additional information: 26
Additional information: 229382

Run Orack and review the HTML file for Errors and Warnings


[root@grac41 orachk]# ./orachk -v
ORACHK  VERSION: 12.1.0.2.3_20150305

[root@grac41 orachk]# ./orachk
CRS stack is running and CRS_HOME is not set. Do you want to set CRS_HOME to /u01/app/11204/grid?[y/n][y]


Check generated HTML file for WARNINGS and ERRORS 
..
Cluster Wide Status 
WARNING => RDBMS software owner UID does not match across cluster

DATA FROM GRAC41 - RDBMS SOFTWARE OWNER UID ACROSS CLUSTER 
uid=54321(oracle) gid=54321(oinstall) groups=54321(oinstall),500(vboxsf),54322(dba),506(asmdba)

DATA FROM GRAC42 - RDBMS SOFTWARE OWNER UID ACROSS CLUSTER 
uid=54321(oracle) gid=54321(oinstall) groups=54321(oinstall),500(vboxsf),54322(dba),506(asmdba)

DATA FROM GRAC43 - RDBMS SOFTWARE OWNER UID ACROSS CLUSTER 
uid=501(grid) gid=54321(oinstall) groups=54321(oinstall),500(vboxsf),54322(dba),504(asmadmin),506(asmdba),507(asmoper) 

-> Here we see easily can see  that uid on GRAC43 is wrong  

Fix the error and verify database status  
[root@grac43 bin]# chown oracle oracle
[root@grac43 bin]# chmod 6751 oracle
[root@grac43 bin]# ls -l oracle
-rwsr-s--x. 1 oracle asmadmin 239732402 Jul 21  2014 oracle
[grid@grac43 ~]$ srvctl start instance -d grac4 -i grac43
[oracle@grac43 dbs]$ srvctl status database -d grac4
Instance grac41 is running on node grac41
Instance grac42 is running on node grac42
Instance grac43 is running on node grac43



WebDriver a perfect API testing your JEE application

Overview

  • Selenium WebDriver marks a leap forward in terms of browser automation
  • WebDriver can be used by multiple Languages : Java, C#, PHP, Phyton, Perl, JS, …
  • Selenium-WebDriver makes direct calls to the browser and can issue Buttons clicks , ..
  • Selenium-WebDriver supports multiple Browers like Firefox , Chrome, HtmlUnitDriver,  …
  • HtmlUnitDriver is a  headless (GUI-less) browser simulator ( good for Load Testing )
  • Before switching to HtmlUnitDriver you may first use  a GUI based Driver like FirefoxDriver

Preparing Test Environment

For testing WebDriver we use 2 Wildfly instances :
Instance 1 (Port 8081 ) : Production  Server  
   publishes our Website to be tested - Session Scoped Bean using following annotations
      @Named("jPATestBean")
      @SessionScoped 
Instance 2 ( Port 8180) : Test Server 
   Simulates a Webbrowser - using following annotations   
      @RunAsClient annotation 
   This project only has a single Java test Class 


Note: The WFJPA2EL-1.0 Web application is deployed to both Server 

 

Testing the same Webapplication running on  different Application Servers

The main purpose of these tests [ test1() and test2() ] are:

  • Review the Page and verify the Page title
  • Dynamically click  the JSF button j_idt8:cBtn32
  • Use View Page Source from your firefox Browser  to find out your IDs for your Button.  Sample:
    <td><input id=“j_idt8:cBtn32” type=”submit” name=”j_idt8:cBtn32″ value=”Check running RAC Instances and JPA Version ” /></td>
  • Verify that we are connecting to the correct  RAC database named:  BANKA
  • Test  using different URLs
    http://localhost:8081/WFJPA2EL-1.0/     http://localhost:8180/WFJPA2EL-1.0/
  • Sleep between HTTP request to allow users to read the HTML page
Java Code
@Test
@RunAsClient
public void test1() throws InterruptedException
{
testJPARunAsClient("http://localhost:8081/WFJPA2EL-1.0/");
}

@Test
@RunAsClient
public void test2() throws InterruptedException
{
testJPARunAsClient("http://localhost:8180/WFJPA2EL-1.0/");
}

public void testJPARunAsClient(String URL) throws InterruptedException
{
String methodName = "testJPARunAsClient()";
System.out.println("Inside: " + methodName + "- URL: " + URL );
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get(URL);
String pageTitle = driver.getTitle();
System.out.println(" URL " + contextPath +  " - " +methodName + " - Found Page Title:  " + pageTitle);
Assert.assertEquals( "Testing RAC - J2EE JPA2 API!", pageTitle);
// Press the Check RAC instance Button
driver.findElement(By.id("j_idt8:cBtn32")).click();
String rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
if ( rtInfo != null )
{
System.out.println(rtInfo);
Assert.assertTrue(rtInfo.contains("DB Name:  BANKA"));
}
// Close brower window after 5 seconds
Thread.sleep(5000);
driver.quit();
System.out.println("Leaving: " + methodName);
}
}

Note our tested URL should return
Inside: testJPARunAsClient()- URL: http://localhost:8081/WFJPA2EL-1.0/
URL http://127.0.0.1:8180/testJPABeanUsingWebdriver/ - testJPARunAsClient() - Found Page Title:  Testing RAC - J2EE JPA2 API!
10:34:11.045 Calling  getRacInfo() in progress ...
10:34:11.046 EclipseLink Version: 2.5.2 - [ EclipseLink 2.5.2 == JPA 2.1]
10:34:11.047 Driver Name             : Oracle JDBC driver
10:34:11.047 Driver Version          : 12.1.0.2.0
10:34:11.048 Database Product Version: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Advanced Analytics and Real Application Testing options
10:34:11.056 DB Name:  BANKA
10:34:11.057 1. Instance Name: bankA_3 - Host: hract21.example.com
10:34:11.057 Leaving getRacInfo() without Exceptions !
Leaving: testJPARunAsClient()

Use View Page Source from firefox to find out our GUI IDs
<td><input id="j_idt8:cBtn32" type="submit" name="j_idt8:cBtn32" value="Check running RAC Instances and JPA Version " /></td>

Starting the test using Maven
$ mvn test

This tests should do the following
- Start 2 firfox browser session and execute the JSF function invoked by j_idt8:cBtn32 button
- After each test the browser should be  closed automatically

The above maven command should return
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 51.583 sec
Results :
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1:06.197s
[INFO] Finished at: Thu Jun 18 15:23:00 CEST 2015
[INFO] Final Memory: 19M/55M
[INFO] ------------------------------------------------------------------------

 

Testing a quite complex JTA transaction application by using multiple Browsers


For running test3() and test4() we use a SessionScoped Web application.
This application runs  the following 5 HTTP request :
 - HTTP Request1: Request the initial page via HTTP GET request
 - HTTP Request2: Cleanup table records
 - HTTP Request3: Uses  a HTTP post request to START and SUSPEND a Transaction 
     - Start a JTA transaction
     - Run JPA flush [ == Insert a new db record )
     - Suspend the JTA transaction using the JEE TransactionManager API
     - Add JTA transaction object, Entity Manager object to our HTTPSession Object 
  - HTTP Request4: Uses  a HTTP post request to RESUME and COMMIT the Transaction      
     - retrieve JTA transaction object and Entity Manager object from our HTTPSession Object
     - Resume the Transaction and update the record
     - Commit the record -  in case of any errors rollback the transaction
     - Cleanup HTTP session object , clear the Entity Manager 
  - HTTP Request5: Uses  a HTTP post request to invalidate the HTTP session          
     - Invalidate the HTTP session 

-> This is a quite complex Transaction sample and we will see whether WebDriver 
   can handle this ! 

The main purpose of these tests [ test3() and test4() ]  are 
- Test a SessionScoped JEE application with different Browser [ Firefox and GUIless HtmlUnitDriver ]
- Track the JSESSIONID cookie 
- test3() uses Firefox Driver  
   - start a Firfox session
   - Display the HTML page 
   - Use wait times to display the HTTP pages 
 
- test4()  uses the GUIless HtmlUnitDriver 
   - don't start any browser and display any HTLM page  ( useful for GUI test )
   - Don't use any wait times between the HTTP requests ( useful for performance test ) 

JAVA Code 
  @Test 
     public void test3() throws InterruptedException
      {
         testJPARunAsClientTestSession("http://localhost:8180/WFJPA2EL-1.0/", true);
      }  
    
     @Test 
     public void test4() throws InterruptedException
      {
         testJPARunAsClientTestSession("http://localhost:8180/WFJPA2EL-1.0/", false);
      }  
      public void testJPARunAsClientTestSession(String URL , boolean useGUI) throws InterruptedException
      {
        WebDriver driver = null; 
        String methodName = "testJPARunAsClient()";
        System.out.println("Inside: " + methodName + "- URL: " + URL );
        if (useGUI)
            driver = new FirefoxDriver();
        else 
            driver = new HtmlUnitDriver();
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); 
        driver.get(URL);  
            //driver.get("http://localhost:8081/WFJPA2EL-1.0/");
            // browser.get("http://localhost:8180/WFJPA2EL-1.0/");
        String pageTitle = driver.getTitle();        
        System.out.println(" URL " + contextPath +  " - " +methodName + " - Found Page Title:  " + pageTitle);
        Assert.assertEquals( "Testing RAC - J2EE JPA2 API!", pageTitle);  
       
            // Press Clean Table Button
        driver.findElement(By.id("j_idt8:cBtn15")).click();       
        String rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
        if ( rtInfo != null )
         {
            if (useGUI)
                System.out.println(rtInfo);
            Assert.assertTrue(rtInfo.contains("Leaving cleanTable() without Exceptions - Data commited"));
         }
        checkCookie(driver, "Action: Clean Table");
        if (useGUI)
            Thread.sleep(2000);
        
            // click Start and Resume Button
        driver.findElement(By.id("j_idt8:cBtn13")).click();       
        rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
        if ( rtInfo != null )
         {
            if (useGUI)
                System.out.println(rtInfo);
            Assert.assertTrue(rtInfo.contains("-> Suspend Transaction - Status: SUSPEND - Salary:1500"));
         }
        checkCookie(driver, "Action: Start and Suspend Transaction");
        if (useGUI)
            Thread.sleep(5000);
        
            // Click Resumee and Commit button
        driver.findElement(By.id("j_idt8:cBtn14")).click();       
        rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
        if ( rtInfo != null )
         {
            if (useGUI)
                    System.out.println(rtInfo);
            Assert.assertTrue(rtInfo.contains("-> Transaction Commited  -  Salary after update:1599"));
         }
        checkCookie(driver, "Action: Resume and Commit Transaction");
        if (useGUI)
            Thread.sleep(10000);
        
               // Click Session Invalidation button
        driver.findElement(By.id("j_idt8:cBtn31")).click();       
        rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
        if ( rtInfo != null )
         {
            System.out.println(rtInfo);          
         }
        checkCookie(driver, "Action: Invalidate JSF session");
        if (useGUI)
            Thread.sleep(1000);
        driver.quit();
      }
     
    private void checkCookie(WebDriver driver, String info)
      {
        Cookie cookie= driver.manage().getCookieNamed("JSESSIONID");
        System.out.println(info + " - JSESSIONID cookie: " + cookie.getValue());
      }
    

Let's verify the Output :  
Action: Clean Table - JSESSIONID cookie: 1ThmlTaJ_TQAqIeltEuixN23.wls1
Action: Start and Suspend Transaction - JSESSIONID cookie: 1ThmlTaJ_TQAqIeltEuixN23.wls1
Action: Resume and Commit Transaction - JSESSIONID cookie: 1ThmlTaJ_TQAqIeltEuixN23.wls1
Action: Invalidate JSF session - JSESSIONID cookie: E9uqbcDsgyCr5aTxu6bQxX26.wls1
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 42.93 sec

-> After invalidation of our JSF session we get a new JSESSIONID cookie - Perfect !

Summary:

  • WebDriver is an easy API for GUI testing and functional testing
  • WebDriver can be used with JMETER ( used for Multithreading testing )
  • WebDriver is able the run even complex JEE application
  • WebDriver perfect deals with the  JSESSIONID cookie

Reference