Sunday, January 22, 2012

WebLogic 10.3.5 Clustering Notes

Official Oracle Documentation on WebLogic Clustering is here
  1. Click here for the recommended architecture
  2. What means of cluster communications are considered ideal?
    The choice is between  Unicast and IP Sockets.  "When creating a new cluster, Oracle recommends that Unicast is used for messaging within a cluster.  Multicast is used only for backwards compatibility".
  3. What about IP sockets?
    It seems that "IP sockets provide a simple, high-performance mechanism for transferring messages and data between two applications". Are IP sockets the best performance alternative? It seems to be.
  4. We should use the native socket reader implementation
    "For best socket performance, configure the WebLogic Server host machine to use the native socket reader implementation for your operating system, rather than the pure-Java implementation." See here for instructions on how to configure native ip sockets
  5. Deployment guidelines:
    1. Even though "partial" deployments are supported, it is better that all Servers in the cluster must are running during deployment
    2. Cluster membership should not change during the deployment process.
  6. Load balancing, Software or Hardware?
    1. Software: use of HttpClusterServlet deployed as a front-end application.
    2. Hardware: Clusters that employ a hardware load balancing solution can use any load balancing algorithm supported by the hardware. These can include advanced load-based balancing strategies that monitor the utilization of individual machines. For load balancing hardware instead of a proxy plug-in, it must support a compatible passive or active cookie persistence mechanism, and SSL persistence.
    3. From this page, It seems that Round-Robin Load Balancing is the only method supported for Servlets/Jsps.  All other methods are for EJBs
  7. Replication
    Coherence*Web seems to be a good option for Http session replication, particularly for large ADF applications that use jbo application modules.  See this page for more info.
  8. Failover
    1. Whole Server Migration: In the event of failure, the whole server is migrated to another web logic server in the cluster.  Used for failover of "pinned" services such as JMS and the JTA
    2. Service Migration: In the event of failure of a service, the service is migrated to another web logic server in the cluster.

To be continued soon...

Saturday, January 21, 2012

Working with the new SQLLocalDB From Microsoft

SQLLocalDB  is a new, lightweight database engine from Microsoft.  You can get it from here.  I have downloaded it and installed the 64 bit version on my Windows 7 laptop.  However, after installation there are no shortcuts created so no gui to manage this "instance".

To start the database engine, open a command line window and type the following:
1.
cd "c:\Program Files\Microsoft SQL Server\110\Tools\Binn"
Substitute for your installation directory.
2. Type:
"SqlLocalDB create "SQL11Local" 11.0 -s"
This will create an sql server instance called "SQL11Local" and start it.
3. Type:
"SQLLocalDB info SQL11Local"
Note the Instance pipe name in the info window.  We will use that to connect to this instance from SQL Server Management Studio

Now start SQL management Studio and in the Server name textbox copy and paste the Instance pipe name from the info command results.  You should connect to the database instance and you can do all the usual things like create , delete and attach databases.

Wednesday, January 11, 2012

Transferring Data Of a Big 9i Oracle Database to 11gR2

Currently I was involved in upgrading a 40 GB Oracle database installation from 9i to 11g release 2. In place upgrade was out of the question since (1) We moved from Solaris to Linux and (2) Downtime should be kept to a minimum

The 9i setup consisted of an Oracle 9i enterprise server, with multiple database instances. One instance had 40 GB of data. This is the procedure we used, which I believe is the quickest way possible to move this amount of data:

On the 9i database server:
  1. Identify and Clear all tables with temporary data.  This includes temporary report tables, backup tables, log tables etc.  In our case, this saved us a gigabyte. 
  2. Export all database intances using the exp utility on the 9i server. Be careful to not allow connections to the database while exporting since sequences can be out of sync.  Do not export the sys user schema.
  3. Create scripts to create tablespaces, schema users and oracle directories 
Now, on the 11g database server
Note: Steps 1, 2 and 3 below can be scripted using bash and sqlplus.
  1. Create all tablespaces on the target 11g database.  Tablespace reorganization complicates the migration so I would advice against it.  Plus, the imp utility expects to find the same tablespaces when importing data of tables with CLOB or BLOB fields    
  2. Create all schema users on the target 11g database.
  3. Create all directories on the target 11g database, both on the database and also on the operating system level and grant the appropriate rights to the appropriate users.
  4. Run import with ROWS=N CONSTRAINTS=Y INDEXFILE=INDEXES.SQL, to create sql statement script for index creation.  Here's an example below.
    $ export ORACLE_SID=ORADB
    $ imp \'sys/oracle as sysdba\' file=/home/oracle/expdat.dmp log=createIndexes.log FROMUSER=oracleuser TOUSER=oracleuser ROWS=n INDEXES=Y CONSTRAINTS=Y INDEXFILE=INDEXES.SQL
  5. Run imp with options ROWS=n INDEXES=N CONSTRAINTS=N STATISTICS=NONE This will create empty tables in the database w/o constraints and indexes, and also import procedures, triggers, and sequences.
  6. Disable Constraints and Triggers in the database.  (click to get the scripts)
  7. Imports table data by running the imp utility with ANALYZE=n BUFFER=100000000 recordlength=65535 FEEDBACK=10000 IGNORE=Y ROWS=Y INDEXES=N CONSTRAINTS=N STATISTICS=NONE
  8. In sqlplus run INDEXES.SQL (created in step 4 above) to create database indexes
  9. Analyze tables in database.  In sqlplus run:
    exec dbms_stats.gather_schema_stats( 
         ownname          => 'oracleuser', 
         estimate_percent => dbms_stats.auto_sample_size, 
         method_opt       => 'for all columns size repeat', 
         degree           => 34 );
    

Thursday, December 15, 2011

PL/SQL to generate insert/update/delete stored procedures for Oracle tables

This pl/sql below creates function sp_generate_procs in the database. You can then call this function to generate insert/update/delete and select procedures. Example usage:
begin
:result := sp_generate_procs(p_table_name => 'candidate');
end;
Function definition:
create or replace function sp_generate_procs(p_table_name varchar2, p_owner varchar2 := null)
    return clob is
    result           clob;
    v_parameters     clob; -- column name parameters
    v_cols           clob; -- plain column names
    v_cols_variables clob; -- column name variables
    vComment         varchar2(1000);
    v_update         varchar2(1000) := 'UDPATE ';
    v_table_name     varchar2(40) := upper(p_table_name);
    v_curr_user      varchar2(100);
    v_colname        varchar2(100);
    v_pkname         varchar2(30);
    v_pktype         varchar2(30);
    v_wasPk          boolean := false;
begin
    /*open c for select *
    from   all_tab_columns
    where  table_name = p_table_name
    and    owner = v_curr_user;*/
    select c.column_name
      into v_pkname
      from user_constraints u, user_cons_columns c
     where u.constraint_type = 'P'
       and u.table_name = c.table_name
       and c.constraint_name = u.constraint_name
       and c.table_name = v_table_name;

    vComment := chr(13) || '--Procedure auto generated by sp_generate_procs on ' || sysdate ||
                chr(13);

    if p_owner is null then
        select SYS_CONTEXT('USERENV', 'CURRENT_USER') into v_curr_user from DUAL;
    else
        v_curr_user := p_owner;
    end if;

    v_update := chr(9) || 'UPDATE ' || v_table_name || ' SET ' || chr(13);

    for c in (select *
                from all_tab_columns
               where table_name = v_table_name
                 and owner = v_curr_user)
    loop
        if lower(v_pkname) = lower(c.column_name) then
            
            v_pktype  := c.data_type;
            v_colname := 'p_' || substr(c.column_name, 1, 28) || ' IN OUT ' || c.data_type;
        else
            v_colname := 'p_' || substr(c.column_name, 1, 28) || ' ' || c.data_type;
        end if;
        dbms_output.put_line(c.column_name);
        --v_colname := 'p_' || c.column_name || ' ' || c.data_type;
    
        if v_parameters is null then
            v_parameters     := chr(9) || chr(9) || v_colname;
            v_cols           := chr(9) || chr(9) || c.column_name;
            v_cols_variables := chr(9) || chr(9) || 'p_' || substr(c.column_name, 1, 28);
        else
            if (v_wasPk) then
                v_parameters := v_parameters || ', -- Primary key is IN/OUT';
                v_wasPk      := false;
            else
                v_parameters := v_parameters || ',';
            end if;
        
            v_parameters     := v_parameters || chr(13) || chr(9) || chr(9) || v_colname;
            v_cols           := v_cols || ',' || chr(13) || chr(9) || chr(9) || c.column_name;
            v_cols_variables := v_cols_variables || ',' || chr(13) || chr(9) || chr(9) || 'p_' ||
                                substr(c.column_name, 1, 28);
        end if;
    
        if lower(v_pkname) != lower(c.column_name) then
            v_update := v_update || chr(9) || chr(9) || c.column_name || '=' || 'p_' ||
                        substr(c.column_name, 1, 28) || ',' || chr(13);
        else
            v_wasPk   := true;
        end if;
    
    end loop;

    v_update := substr(v_update, 1, length(v_update) - 2);
    v_update := v_update || chr(13) || chr(9) || 'where ' || v_pkname || '= p_' || v_pkname || ';' ||
                chr(13);

    result := result || 'CREATE OR REPLACE PROCEDURE ' || v_table_name || '_SELECT (p_' || v_pkname || ' ' ||
              v_pktype || ',curs out sys_refcursor) AS ' || chr(13);
    result := result || vComment || 'begin' || chr(13);
    result := result || 'open curs for ' || chr(13);
    result := result || chr(9) || 'select ' || chr(13) || v_cols || chr(13) || chr(9) || ' from ' ||
              v_table_name || ' where ' || v_pkname || '= p_' || v_pkname || ';' || chr(13);
    result := result || chr(13);
    result := result || 'END;' || chr(13);
    result := result || '/' || chr(13);

    result := result || 'CREATE OR REPLACE PROCEDURE ' || v_table_name || '_INSERT (' || chr(13);
    result := result || v_parameters || ') AS ' || chr(13);
    result := result || vComment || 'begin' || chr(13);
    result := result || chr(9) || 'insert into ' || v_table_name || '(' || chr(13);
    result := result || v_cols || chr(13) || chr(9) || ') values (' || chr(13) || v_cols_variables || ');' ||
              chr(13);
    result := result || chr(13);
    result := result || 'END;' || chr(13);
    result := result || '/' || chr(13);

    result := result || 'CREATE OR REPLACE PROCEDURE ' || v_table_name || '_UPDATE (' || chr(13);
    result := result || v_parameters || ') AS ' || chr(13);
    result := result || 'begin' || chr(13) || vComment || chr(13);
    result := result || v_update;
    result := result || 'END;' || chr(13);
    result := result || '/' || chr(13);
    result := result || 'CREATE OR REPLACE PROCEDURE ' || v_table_name || '_DELETE(p_' || v_pkname || ' ' ||
              v_pktype || ') AS ' || chr(13);
    result := result || 'begin' || chr(13);
    result := result || chr(9) || 'delete from ' || v_table_name;
    result := result || chr(9) || ' where ' || v_pkname || '= p_' || v_pkname || ';' || chr(13);
    result := result || chr(13);
    result := result || 'END;' || chr(13);
    result := result || '/' || chr(13);
    return(result);

end sp_generate_procs;
/

Wednesday, December 7, 2011

Copying a Weblogic 10.3.5 domain to another server.

It seems that it is possible to file copy a weblogic domain to another server.
In fact we tried xopy on a windows server the whole weblogic server installation and it worked like a charm. See this post
It is a little more complicated than a plain copy if your server uses SSL (read below)

You can file copy a weblogic domain to another server provided that:

  1. The servers have identical directory structure for MIDDLEWARE_HOME.  In our case, it was /u01/app/oracle/product/middleware
  2. The linux username is the same.  In our case, it was oracle.
  3. The Fusion Middleware version is the same.  In our case it was 11.1.2.0
  4. There is no cluster configured in the domain.  

Steps Involved:
  1. Shutdown all weblogic servers and node manage in source server.
  2. Go to the 'AdminServer' root directory (should be under  $MIDDLEWARE_HOME/user_projects/domains/domain name/servers/AdminServer ) and delete all sub-directories except the "security" directory. This includes tmp, data, cache, etc .  Do the same for all managed servers in the domain
  3. Switch to domain root and execute command below to create a tar file with the domain contents.
    $ cd $MIDDLEWARE_HOME/user_projects/domains/
    $ tar -cvf mydomain.tar ./mydomain
  4. Ftp / copy tar file to target server 
  5. Login to target using weblogic server's user username and execute command below to extract tar file.
    $ cd $MIDDLEWARE_HOME/user_projects/domains
    $ tar -xvf domain.tar
    
  6. After extraction of domain files:
    1. Update the domain registry of weblogic installation to include the new domain.
    2. You will have to search and replace the source machine's hostname with the targets machine's hostname inside any non binary file in the MIDDLEWARE_HOME. For our web logic installation it was only in 1 file. For the Middleware home, it was multiple files.
    3. ONLY for servers that utilize SSL:Generate a new DemoIdentity.jks file for use with nodemanager (The one copied over was for source host).
    4. $ cd $MIDDLEWARE_HOME/wlserver_10.3/server/lib/
      $ . ../bin/setWLSEnv.sh
      $ java utils.CertGen -cn targethost.com -keyfilepass
      $ java utils.CertGen -cn targethost.com -keyfilepass DemoIdentityPassPhrase -certfile testcert -keyfile testkey
      $ java utils.ImportPrivateKey newkeystore.jks DemoIdentityKeyStorePassPhrase demoidentity DemoIdentityPassPhrase testcert.pem testkey.pem
      $ keytool -v -list -keystore newkeystore.jks -storepass DemoIdentityKeyStorePassPhrase
      $ cp newkeystore.jks DemoIdentity.jks
      
  7. Finally start the WebLogic nodemanager and servers on the target machine and verify that all is OK.

Tuesday, December 6, 2011

Yes, you can XCOPY a weblogic installation to another server

On Windows Servers (2003/2008), it is possible to xcopy the whole weblogic installation from one server to another, and it will actually work: All domains, servers and deployments work as expected. Even the Fusion Middleware worked as expected, with all the patches and megabytes of jars that Oracle shovels into the installation.

It goes without saying that: (1) the directory structure between the 2 servers should be identical, ie if on source Server weblogic was installed on c:\oracle\middleware, then on Server 2 it should be the same, (2) The Java jdk is installed at exactly the same path and (3) You will have to search and replace the hostnames inside configuration files in the installation.
While on destination server and assuming the source server is available over the network, the xcopy command is this:

xcopy \\server1\c$\oracle\middleware c:\oracle\middleware /E/ H
It is even a better approach to tar and compress the directory and then copy it. Just be sure to include any hidden files.

This is useful in cases where:

  • You need to transfer an installation to another server, for example a failover server
  • You need to transfer an installation from a staging virtual machine to production
  • You need to restore a corrupted weblogic domain from backup.

Friday, November 25, 2011

SQL Plus script to disable/enable all triggers an Oracle database

Below is an SQL Plus script to disable/enable all triggers for the current user in an Oracle database.  This is useful when importing data in an oracle database and you do not want triggers firing.  Substitute "DISABLE" below with "ENABLE" to enable back triggers after data import.

begin
  for c in (select * from user_triggers a where a.trigger_name not like '%$xd' )
  loop
      execute immediate('alter trigger '||c.trigger_name||' DISABLE');
  end loop;
end;