Posted on

20 years with Linux

I don’t recall the date that I installed Linux for the first time, but it was some months before the 1.0 kernel was released in March 1994, so the 20 year anniversary is approaching or already past. I believe that Linux is the most influential technology in all of my life. My kids grew up using KDE and GNOME instead of Windows. I was doing NAT in a critical business environment years before it was available in consumer-grade WiFi routers (or even called NAT, then it was IP Masquerading). I solved real problems with Linux over and over again, and I flourished as a hacker with all of the knowledge freely available about Linux on the internet.
Back then, I could not have imagined the extent of Linux’s domination as an operating system. It was joked about on mailing lists, but I never thought it would come true. I’m happy that it did, I feel vindicated in my early adoption and continuous advocacy of Linux in the business world. Now my voice is no longer even needed as the general IT population has picked up the chorus.
You’d think after 20 years I would know it all, but that’s far from the case and I’m still learning about this fantastic OS and it’s capabilities. It’s fun and exciting to know there are always additional things to master. I moved my career over to Oracle database administration 16 years ago, and find much of the same utility there, with the addition of a lot more complexity, but I still love to use the bash shell and vi will always be my editor of choice. The foundation of Unix, enhanced dramatically by my experience with Linux, has made me a far better DBA than I would have been otherwise.
Thank you Linus, for putting your work out there and accidentally starting something great.
Posted on

Editioning – Releasing code transparently

We left off with you in a confirmed correct edition in a sqlplus session. At this point you run your regular deploy scripts and re-compile any invalid objects. Now you are ready to test the new release.
Since you deployed to the non-default edition, all your live sessions are still running the same as before, you are the only session that sees the new code. In order to test, you want some other sessions to use this non-default edition. You will need to decide how you want to control this, but I will assume you will use cluster-ready services. To do that, create two new services, one for each edition and set the edition for each service with the -t option to srvctl. Then change the service name your app uses to connect to the one that uses the non-default edition. Then test as long as you wish, you are still in this isolated environment and your regular connections are still unaffected by all of your deploy and testing operations.
When you are finally ready to “go live”, simply change the default edition in the database. There are, of course, considerations outside the database, in upgrading other code and making sure it matches the code in the edition that you are connecting to. Give some thought to how the various parts work together when devising your deploy procedures.
Rollback is pretty obvious here, you simple switch the edition back and you are where you were before the deploy started. It doesn’t get much simpler than that!
Posted on

Editioning – Deploy code to an inactive edition

Last time I discussed controlling which edition a session connects with. This is crucial when actually deploying code. If you  deploy code to an edition with active sessions, you can disrupt those sessions (which negates the point of editioning), or you may find them blocking your code deploy with locks. To avoid this, may sure that no sessions are using the edition you intend to deploy to, and then make very sure you are in the intended edition before starting to deploy code.
I’m assuming that you will be deploying with scripts run by sqlplus, and that the live sessions are using the default edition. These are the steps you should take before deploying any code:
  1. Determine the correct edition. If you are using the two edition method, simply find the default edition and pick the other one, hereafter known as the “deploy edition”.
  2. Connect as the deploy edition using one of the methods outlined in the previous post.
  3. Verify that the current edition is the deploy edition, and that it is not the default edition.
  4. Verify that no other sessions that use the code you are deploying are using the deploy edition.
You will want to script all of this, not have to run the checks manually, but it’s good to understand how to run the checks for occasions when they fail, so you know how to fix the issues.
Determine the deploy edition
# Get the current default edition
DEF_EDITION=`sqlplus -s / as sysdba <<!
set head off
set feed off
set pages 0
select property_value from database_properties where property_name = ‘DEFAULT_EDITION’;
!`
# now switch the edition name
[ ${DEF_EDITION} = “BLACK” ] && DEPLOY_EDITION=WHITE || DEPLOY_EDITION=BLACK
Connect with the deploy edition
ORA_EDITION=${DEPLOY_EDITION}
sqlplus / as sysdba
– or –
sqlplus / as sysdba edition=${DEPLOY_EDITION}
Verify that we are ok to deploy to the current edition
SELECT sys_context(‘USERENV’, ‘CURRENT_EDITION_NAME’) “Current Edition” FROM dual;
WHENEVER SQLERROR EXIT
SET SERVEROUT ON SIZE UNLIMITED
DECLARE
e_halt_processing EXCEPTION;
v_edition varchar2(35);
  v_sess_cnt pls_integer;
BEGIN
SELECT sys_context(‘USERENV’, ‘CURRENT_EDITION_NAME’) INTO v_edition FROM dual;
— check that we are in the correct edition
IF v_edition <> ‘${DEPLOY_EDITION}’ THEN
DBMS_OUTPUT.PUT_LINE(‘Deploy halted – edition not set properly!!’);
RAISE e_halt_processing;
END IF;
— check that it’s not the default edition
  SELECT property_value INTO v_edition FROM database_properties WHERE property_name = ‘DEFAULT_EDITION’;
IF v_edition = ‘${DEPLOY_EDITION}’ THEN
DBMS_OUTPUT.PUT_LINE(‘Deploy halted – this is the default edition !!’);
RAISE e_halt_processing;
END IF;
— check that no app sessions are using the edition we are deploying to
SELECT COUNT(*) INTO v_sess_cnt FROM sys.gv$session s LEFT OUTER JOIN sys.dba_objects o ON (s.session_edition_id = o.object_id)
 WHERE username IN (‘APP1′,’APP2′,’APP3’)  AND s.status <> ‘KILLED’
 AND o.object_name = ‘${DEPLOY_EDITION}’;
  IF v_sess_cnt > 0 THEN
     DBMS_OUTPUT.PUT_LINE(‘Deploy halted – sessions are using this edition !!’);
     RAISE e_halt_processing;
  END IF;
END;
/
WHENEVER SQLERROR CONTINUE
Posted on

Editioning – Controlling the edition in use

You have your editions, and you can tell which edition each session is currently using, now how do you control that?

First we’ll look at sessions that you control. If you, or code under your control, initiates the edition, you can control the edition with an ALTER SESSION command, like this:

alter session set edition=MYEDITION;

There are shortcuts to this. When using sqlplus, you can set the ORA_EDITION env var or pass the edition on the command line like this:

sqlplus / as sysdba edition=MYEDITION

Note that although the SYS user cannot have editions enabled, it is still true that every login session has a current edition, since it may access objects owned by users that do have editions enabled.

Some other tools may allow you to set an edition for a database connection. This is really all just making the alter sessions command automatic.

You can change the edition in a session as often as you wish, but you cannot be in a place where changing the edition would make the current context invalid. For example, you may not change the edition inside PL/SQL because then you might be executing code from the old edition in the context of the new edition. I know you were thinking of login triggers to change the edition, but you can forget that.

So what about sessions that you don’t control in any way? If they are already running, you cannot change their edition. Think about the havoc that would wreck if it was allowed!

You can however influence the edition that they connect with. I say influence because the session can override your setting with an alter session of their own. The main way you do this is by changing the default edition for the entire database. Think of the default edition as the stable, steady state between code deploys. With no other intervention, all sessions connect as this edition and everything is consistent.

What if you want only certain sessions to connect with the newly deployed code in a non-default edition? The ideal way is to have those sessions make the alter session command, but if you don’t want to do that you have one final option, cluster-ready services.

The -t option to the srvctl modify service command will allow you to specify the edition for that service. Be careful in implementing this, it doesn’t always work reliably, but it’s the best option for controlling the connections of general apps. For one thing, please resist the temptation to use the dbms_services package to change the edition. It has all the options needed and will change the edition in the DBA_SERVICES view, but it will not change it in CRS correctly. Another bug is that if you try to unset the edition with the srvctl command (with -r “”), that will remove it from CRS (as shown by srvctl config), but leave it in the data dictionary, so then you must use the services package as a second step to truly clear it back to use the default edition.

My recommendation is that you not alter the edition of a service to effect this change, but create separate services for each edition and change the service name in the connect details the session will use. Editing the tnsnames.ora on the webserver for example.

Posted on

Editioning – Which edition is a session using?

So now you have 2 editions that have identical objects, one of them is set as the database default edition. How can you tell which edition a session is using?

If you are controlling the session and can run SQL, just run this:

SELECT sys_context(‘USERENV’, ‘CURRENT_EDITION_NAME’) edition FROM dual;

If you want to see what the current edition of other running sessions, try this:

SELECT o.object_name edition, s.*
FROM gv$session s
LEFT OUTER JOIN dba_objects o ON (s.session_edition_id = o.object_id);

Want to know the what the default edition is set to? Run this:

SELECT property_value FROM database_properties WHERE property_name = ‘DEFAULT_EDITION’;

Combining those, if you want to find all the sessions that are using a non-default edition, this will give you that information:

SELECT o.object_name edition, s.*
FROM gv$session s
LEFT OUTER JOIN dba_objects o ON (s.session_edition_id = o.object_id)
WHERE o.object_name NOT IN (SELECT property_value FROM database_properties WHERE property_name = ‘DEFAULT_EDITION’);

So now you know what edition a session is running, next time we’ll talk about how to change the edition and control how other sessions connect.