Monday, March 20, 2017

Oracle Database 12c Perl Distribution and VirtualBox/VMware

The Perl 5.14.1 distribution included with the Oracle 12c Database instance is flawed and crashes when given the true CPUID for the processor. This can happen in several cases, especially when installed on MacOS, VirtualBox, or VMware with newer Intel processors.

This behavior, and solutions, is documented in several places, including here by Laurent Leturgez and here by Danny Bryant. Most noticeably, it occurs when the Perl scripts are run during the creation of a multitenant database using dbca.

The problem hit me hard using virtual computers during a customized Oracle boot camp I am teaching as I write this. The purpose is to document what I found out and how I decided to fix it.

Possible Solution #1 - Modify the Virtual Machine to mask the CPUID

Speaking as a software developer instead of as an Oracle DBA, I really do not like this solution. First of all, modifying the CPUID so that Oracle's version of Perl works risks breaking any other software that relies on the CPUID. If the Oracle Database is the only thing on the virtual computer then it is probably OK. However, this only works for virtual machines. It will not work if the installation is on an operating system installed directly on hardware with a newer Intel CPU, such as MacOS or even some Linux installations.

Oracle VirtualBox

Danny's solution (copied here, all credit goes to him) is to modify the Virtual Box settings to mask the CPUID that the virtual computer receives. This was handled in some instances of Virtual Box, but seems to be unset again in the most recent version that I have (5.1.18).

These seven commands need to be run at the command line on the host computer. In Microsoft Windows if VBoxManage is not in your path, it is probably located in C:\Program Files\Oracle\VirtualBox. Change to that directory and run the commands there. You need to change <VM name> to the name of your virtual computer. Make sure the virtual computer is shut down when you run these commands:

VBoxManage setextradata <VM name> "VBoxInternal/CPUM/HostCPUID/Cache/Leaf" "0x4"
VBoxManage setextradata <VM name> "VBoxInternal/CPUM/HostCPUID/Cache/SubLeaf" "0x4"
VBoxManage setextradata <VM name> "VBoxInternal/CPUM/HostCPUID/Cache/eax" "0"
VBoxManage setextradata <VM name> "VBoxInternal/CPUM/HostCPUID/Cache/ebx" "0"
VBoxManage setextradata <VM name> "VBoxInternal/CPUM/HostCPUID/Cache/ecx" "0"
VBoxManage setextradata <VM name> "VBoxInternal/CPUM/HostCPUID/Cache/edx" "0"
VBoxManage setextradata <VM name> "VBoxInternal/CPUM/HostCPUID/Cache/SubLeafMask" "0xffffffff"


VMware

Danny only addressed VirtualBox, but these similar settings that can be applied to a VMware virtual computer. Find the directory that has the files for the virtual computer, and edit the control file with the ".vmx" extension. Add these lines to the end of the file:

cpuid.4.4.eax = "00000000000000000000000000000000"
cpuid.4.4.ebx = "00000000000000000000000000000000"
cpuid.4.4.ecx = "00000000000000000000000000000000"
cpuid.4.4.edx = "00000000000000000000000000000000"

It seems that it may be necessary to restart VMware itself to get to refresh any cached control files for the instance that it may have, before starting the virtual computer that was changed.

Preferred Solution #2 - Fix Perl

Fixing the Perl that Oracle is using, identified by Laurent Leturgez and all credit goes to him, is really the preferred solution because it does not affect anything else on the system. Laurent gives a quick script to fix things, I will approach this as a series of commands, take things in a little different order, and go into a little more detail about what Laurent's solution does with a few small improvements. Doing it this way might be easier for some people to follow.

The first step is to move the Perl installed with Oracle and create a new Perl directory. We will need some stuff from from the original installation later on. All of these commands should be executed at the command line by the "oracle" user that owns the Oracle Database installation. We will refer to that user as oracle from now on. The $ represents the shell prompt. I assume that $ORACLE_HOME has been set to your installation directory:

$ cd $ORACLE_HOME
$ mv perl/ perl.OLD
$ mkdir perl

Next we need to get and build Perl from the source, specifically we need version 5.14.1. In the oracle user home directory (not $ORACLE_HOME, the user home directory!) make a perl folder. Change directory into the perl folder, and use curl to load the correct source file. Un-tar the source file to make the source directory:

$ cd
$ mkdir perl
$ cd perl
$ curl -O http://www.cpan.org/src/5.0/perl-5.14.1.tar.gz
$ tar -xvzf perl-5.14.1.tar.gz

Both "make" and the GCC compiler need to be installed to build Perl. You may already have them. On RedHat (CentOS, Fedora Core, Oracle Linux) run this command as root (su or sudo) to make sure everything is up to date, or install whatever is missing:

$ yum install make gcc

For Ubuntu, run this command as root (su or sudo):

$ apt-get install make gcc

If you are trying to build this specific Perl on MacOS it is a bit more difficult to get the tools. This post by Yong Mook Kim should help you if you do not have gcc and make installed.

Now we are ready to build a working Perl installation. Change directory to the source for perl: ~oracle/perl/perl-5.14.1. Run the following commands to configure the build, make Perl from the source, and install Perl into $ORACLE_HOME/perl:

$ ./Configure -des -Dprefix=$ORACLE_HOME/perl -Doptimize=-O3 -Dusethreads -Duseithreads -Duserelocatableinc
$ make
$ make install

Change directory to $ORACLE_HOME/perl. We need the specific libraries that Oracle provided, and there is nothing wrong with those libraries from the original Oracle perl. We also need a handful of special programs from the bin folder. There is nothing wrong with the manual pages, so we will ignore those:

$ cd $ORACLE_HOME/perl
$ rm -rf lib
$ cp -r ../perl.OLD/lib/ lib
$ cp ../perl.OLD/bin/dbilogstrip bin
$ cp ../perl.OLD/bin/dbiprof bin
$ cp ../perl.OLD/bin/dbiproxy bin
$ cp ../perl.OLD/bin/ora_explain bin

That should take care of everything. Run $ORACLE_HOME/perl/bin/perl -v to verify that Perl does run. Now dbca should not fail when it tries to launch a perl script; one test would be to build a multitenant database using dbca.

No comments:

Post a Comment