Thursday, September 6, 2012

OAT: monitor dbspace usage / Monitorização de ocupação de dbspaces

This article is written in English and Portuguese
Este artigo está escrito em Inglês e Português

English version:

I keep working with OAT and the database scheduler and It keeps causing me a very good impression. The fact is that we can really get a structured way to deal with typical issues. The example I'll put here in this article is trivial, and every serious DBA has dealt with it. So, in a sense it doesn't bring anything new. Why the trouble? Because it serves as a very nice example on how things can fit together. During this article I'll show you how to take advantage of some components that you probably already use (alarmprogram and OAT) to build a robust, simple, configurable and also important, elegant space usage monitoring.

I'm sure you probably already have a script to monitor your space usage, so you may be thinking how will I convince you to dump it and use this. Let's see what are the usual issues with that kind of scripts:
  1. Typically they're launched by cron. Strangely or not, some customers are restricting the usage of cron. Hopefully this is not your case.
  2. Typically the scripts have the mechanism to send alarms inside them. If you need to change anything (email addresses, phone or page numbers), you may have to change several scripts
  3. Most of the times the scripts don't have "memory". Meaning for example, they'll keep sending alarms forever. In some cases this maybe useless and annoying.
  4. Since the scripts don't have "memory", they will not "clear" the alarm if the problem is solved
  5. The scripts typically will not send info to OAT. And OAT is elegant and easy to use
  6. Typically, different dbspaces in different instances will have acceptable usage thresholds different from each other. This means the scripts need to be more complex to allow customization
I think I could get a few more issues, but the above 6 will be enough. So, my value proposition is to create a mechanism that will solve all the issues above, and that also have some other advantages:
  • You can use is as a skeleton to build other monitoring tasks
  • It's all configurable within the database
As mentioned above we'll need several components:
  1. A fully functional ALARMPROGRAM script
    You should already have this, but some more customization will need to be implemented (a few lines)
  2. Open Admin Tool up and running
  3. Database scheduler active
  4. A procedure to call the ALARMPROGRAM script
    I took a look at a recent article from Andrew Ford about auto-extending dbspaces. He also has an example of a procedure to do this.
So, let's begin:

ALARMPROGRAM script changes


You should create a new class for the event generated by this monitoring task. I noticed Andrew recommends adding two classes (101 and 102 in his example), but I prefer to add just one and leave the decision to send email or paging/sms to the other ALARMPROGRAM parameter, the "severity". In fact I typically use a customized ALARMPROGRAM script where I can define that all events with a certain severity will send a short message and with lower will just send an email, or otherwise define a set of classes that send emails or sms independently of the severity

In any case configure and test your ALARMPROGRAM to receive another class and act accordingly to your needs. The advantage of using an ALARMPROGRAM script is that it becomes the only place where you'll need to change email addresses, pager or SMS numbers etc. Once configured it will work perfectly for you, and be re-usable for any kind of monitoring.

Open Admin Tool up and running

As you'll see, this task will generate alerts in the OAT screen. So you'll have something to show to your management. Typically they like to see some fancy graphics... You'll also be able to change the schedule and configuration of the task (including the thresholds). More on this later, as I have one complain about OAT :)

Database scheduler active

As already mentioned, this monitoring tool is implemented as a task in the database scheduler (introduced in version 11). So this is a requirement.

A procedure to call the ALARMPROGRAM script

As mentioned before, we'll need a procedure to call the ALARMPROGRAM script. This procedure will basically receive the parameters, construct a command and make a SYSTEM() call. The path of the ALARPROGRAM script will be queried from the sysmaster database. So if you ever want to change your script location you don't have to worry about this procedure. It will automatically adapt. The code for this procedure can be found in Listing 1 at the end of the article.
This procedure will be called in several places inside our monitoring task.


The task itself: Description and setup

The free space monitoring task is implemented as a stored procedure. You can find it in Listing 2 below. Let's check it nearly line by line.


  • Lines 1 and 2 are just the DROP/CREATE instructions. Notice that the procedure takes two arguments that are really great and helpful as we'll see later:
    task_id is the id in the ph_task table. It's unique for each task and allows us to cross reference several other tables in sysadmin
    v_id is the execution number of this task. It will change (increment) each time this task is executed
  • The next lines, up to 19, are just variable definitions. I won't explain them since they'll appear in several comments below
  • Lines 20 to 25 refer to debugging instructions. Just uncomment the lines 23 and 24 to get a trace of the task execution in a file created in your /tmp directory (obviously this can be changed)
  • Lines 29 to 31 are very important. The values defined are the last resort used by the task if all the other configuration parameters aren't in place. The defaults defined are:
    default yellow threshold (90): This will represent the percentage of use for each dbspace, above which an alarm of severity 3 will be raised
    default red threshold (95): This will represent the percentage of use for each dbspace, above which an alarm of severity 4 will be raised
    number of alarms (3): This will represent the number of alarms to send. A number of 0 will mean it will keep sending alarms until the situation is solved.

    As we shall see next, these values can be overridden by values configured in the task configuration, and the red/yellow threshold can be configured by dbspace. The above values will only be used if the other more specific configuration items are not setup. And of course, you can change these values in the code, so that they meet your environment.
  • Line 33 is very important since it defines the ALARMPROGRAM class number for lack of space in one dbspace. You should adjust these to the value you added to your ALARMPROGRAM. I use values above 900 for my "personal" extensions so that they won't match classes added to ALARMPROGRAM by IBM in the future (we'll never know how many will be added, but 900 seems a reasonable gap...)
  • Lines 35 to 93. Here we will try to get the defaults that were configured for the above values. These defaults are configuration items for the task. Unfortunately, current OAT versions don't allow us to use the GUI to setup these initial values. We have to create them using SQL. After that they can be changed using OAT's GUI.... I'd like to see the wizard for a new task creation to include the configuration of any task configuration items.... But it isn't there at this moment (version 2.28...). So we need to insert them via SQL. How to do it: These values are kept in the ph_threshold table, which has the following fields:
    name: This is the parameter name. In our case we have the following: DEFAULT NUM ALARMS, DBSPACE YELLOW DEFAULT, DBSPACE RED DEFAULT and then we can insert any in the forms DBSPACE YELLOW dbspace_name and DBSPACE RED dbspace_name. I think the names are self explanatory. The idea is that if you want to create red/yellow thresholds for specific dbspaces you'll have to insert the DBSPACE RED/YELLOW dbspace_name parameters in the ph_thresholds table. If there isn't a specific value for a certain dbspace it will use the value specified in the DBSPACE RED/YELLOW DEFAULT parameter. If these are also not defined, it will use the values defined in lines 29 to 31.
    task_name: the name of the task from the ph_task table. This value needs to match whatever name we give to the task and that's the one we will use to create the entry in the scheduler. For the purpose of this article I'll use IXMon Check Space. You can use whatever you want, as long as you're consistent.
    value: the value of the threshold. This will be the value to be used by the task. In our case, the DBSPACE RED/YELLOW * parameters will use percentage values (1-100)
    value_type: the data type of the threshold (STRING or NUMERIC). In our case we'll use NUMERIC. From some investigation I noticed that we can use NUMERIC(x,y) for non integer values. I didn't test it, but it should work in case it makes sense for you.
    description: a description of what the threshold does. This will be visible in the OAT's GUI if later you want to change the values using the GUI.

    So, to give you some examples, I'll just show the instructions used to create the values that are also specified in the code (number of alarms, red and yellow default thresholds). I'll use the same values:



    INSERT INTO ph_threshold ( name, task_name, value, value_type, description)
    VALUES ( 'DEFAULT NUM ALARMS', 'IXMon Check Space', '3', 'NUMERIC', 'Number of alarms to send');
    INSERT INTO ph_threshold ( name, task_name, value, value_type, description)
    VALUES ( 'DBSPACE YELLOW DEFAULT', 'IXMon Check Space', '90', 'NUMERIC', 'Generic yellow threshiold. It will be applied to any dbspace lacking a specific threshold');
    INSERT INTO ph_threshold ( name, task_name, value, value_type, description)
    VALUES ( 'DBSPACE RED DEFAULT', 'IXMon Check Space', '95', 'NUMERIC', 'Generic red threshiold. It will be applied to any dbspace lacking a specific threshold');


    And for example, if you have a dbspace called llogs_dbs, dedicated to logical logs which is nearly full and which doesn't make too much sense to monitor you could add:


    INSERT INTO ph_threshold ( name, task_name, value, value_type, description)
    VALUES ( 'DEFAULT YELLOW llogs_dbs', 'IXMon Check Space', '100', 'NUMERIC', 'Make llogs_dbs pass all tests....');
    INSERT INTO ph_threshold ( name, task_name, value, value_type, description)
    VALUES ( 'DEFAULT RED llogs_dbs', 'IXMon Check Space', '100', 'NUMERIC', 'Make llogs_dbs pass all tests....');


  • Line 97 creates a FOREACH loop. It's based on the query in the next lines which will check the used space in every dbspace in the system
  • Lines 98 to 111. This is the dbspace usage query. Some parts of it might not be necessary, but I took the query from another script... Don't worry, it should work. It gives the number of the pages and the number of free pages in all the dbspace chunks grouped together.
    Notice that the task is based on usage percentage. It could be improved to handle other types of parameters, like allocated GB, or free GB etc. For now I kept it simple....
  • Lines 114 to 153 are used just to try to find specific thresholds for the dbspace we're processing. If they're not found in the ph_threshold table the generic defaults will be used.
  • Lines 154 to 172. Here we calculate the used space percentage and check it against the red and yellow thresholds. If we're beyond any of these values we'll define an alert color and the alert message. If we're below the yellow threshold we leave the color as NULL.
  • Lines 175 to 200. If our current dbspace usage is below the yellow threshold we look for an alert in the ph_alert table for this specific dbspace with state equal to "NEW". If we find one we update it, changing it's state to "ADDRESSED". This can happen if after an alarm was generated someone drops a table for example. In this case I'm not calling the ALARMPROGRAM, but it could make sense to call it with a message like "Previous alarm for dbspace_name is canceled because it's now below the defined thresholds"
  • From 204 till the end, we have exceeded one of the thresholds.... So... First we query ph_alert to see if we have an alarm for this dbspace in the state "NEW". If we don't (223 - 239) we insert it and call the ALARMPROGRAM using the procedure above. If we already have an alarm we check if it's the same color. If it's not (244 - 252), we update two fields:
    alert_task_seq: we do this to reset the alarm counter
    alert_color: we update the color code of the alarm (for usage in OAT's GUI. Note that at this time we may have a RED alert with an YELLOW message text. I choose to do this, to show that there was a change between the current and previous situation. If the alarm has the same color than we check the field alert_task_seq and compare it with our task execution number (given as a parameter to the procedure) and decide, based on the configured number of alarms if we should call ALARMPROGRAM or not

So, finally, how do we schedule the task? Well you can do it by using OAT's GUI or if you want you can insert it directly into the ph_task table:


INSERT INTO ph_task
(
tk_id, tk_name, tk_description, tk_type, tk_dbs,
tk_execute, tk_start_time, tk_frequency,
k_monday, tk_tuesday, tk_wednesday, tk_thursday,
tk_friday, tk_saturday, tk_sunday,
tk_group, tk_enable, tk_priority
)
VALUES
(
0, 'IXMon Check Space', 'Check dbspace free space', 'TASK', 'sysadmin',
'ixmon_check_space', '00:00:00', '0 00:30:00',
't', 't', 't', 't', 't', 't', 't',
'USER','t',0
)



UPDATE [ 20 Aug 2010]:
I missed and IF block wrapping the UPDATE to move the existing alarm to the state ADDRESSED (lines 195-200). Like it was, it would try the update even if we didn't find an alert... This was not very serious, but it you want to call ALARMPROGRAM when the alert conditions clear up, then you need this IF or it will send alarms for every dbspace that is below the thresholds.... Sorry about this mess... So I added the IF on line 194 and the END IF on line 201.

Versão Portuguesa:

Conitnuo a trabalhar com o Open Admin Tool (OAT) e o scheduler de tarefas da base de dados e continuo a ficar bem impressionado com ambos. A verdade é que nos permitem uma abordagem estruturada na gestão de questões típicas. O exemplo que vou deixar neste artigo refere-se a um assunto trivial e qualquer DBA já se deparou com o mesmo. Neste sentido não trás nada de novo. Assim, porquê o trabalho? Porque serve como excelente exemplo de como as coisas se podem encaixar. Ao longo deste artico tentarei mostrar como tirar proveito de alguns componentes que provavelmente já utiliza nas suas instâncias (ALARMPROGRAM e OAT) para construir um mecanismo de monitorização de espaço utilizado que se pretende robusto, simples, configurável e igualmente importante, elegante.

Tenho a certeza que provavelmente já terá um script para monitorizar este aspecto, pelo que poderá estar a pensar como é que o vou convencer a desistir do mesmo e utilizar este (ou algo construído com base neste). Vejamos quais são os problemas habituais destes sripts:

  1. Normalmente são lançados pelo cron. Estranhamente ou não, alguns clientes estão a restringir a utilização do cron. Com sorte este não será o seu caso.
  2. Muitas vezes os scripts têm mecanismos para enviar alarmes dentro deles. Se necessitar de mudar alguma coisa (endereços de email, números de telefone ou pagers) poderá ter de mudar vários scripts.
  3. Na maioria dos casos os scripts não têm "memória". Isto quererá dizer, por exemplo, que continuarão a enviar alarmes sempre (enquanto o problema se mantiver). Em algumas situações isto pode ser inútil e irritante.
  4. Como os scripts não têm "memória" eles não irão "limpar" um alarme caso se verifique que o problema se resolveu.
  5. Em principio os scripts não enviam informação ao OAT. E o OAT é elegante e fácil de utilizar.
  6. Tradicionalmente, diferentes dbspaces em diferentes instâncias terão valores de ocupação aceitável diferentes uns dos outros. Isto obriga a maior complexidade dos scripts para permitir a customização.
Provavelmente conseguiria referir mais alguns problemas, mas os 6 acima deverão ser suficientes. Assim, a minha proposta de valor é criar um mecanismo que resolva todos os problemas acima, mas que traga também algumas outras vantagens:
  • Possa ser utilizado como esqueleto para outras operações de monitorização
  • Seja configurável exclusivamente dentro da própria base de dados
Como referi anteriormente iremos necessitar de vários componentes:
  1. Um script de ALARPROGRAM completamente funcional
    Já deverá ter isto, mas serão necessárias algumas alterações (poucas linhas)
  2. Open Admin Tool a funcionar
  3. O scheduler da base de dados activo
  4. Um procedimento ou função para chamar o script ALARMPROGRAM
    Li recentement um artigo do Andre Ford sobre como auto-estender os dbspaces. Nesse mesmo artigo também há um exemplo de um procedimento para efectuar isto
Comecemos então:

Alterações no script ALARMPROGRAM


Deverá criar uma nova classe para o evento gerado por esta tarefa de monitorização. Notei que o Andrew Ford indica a criação de duas classes (101 e 102 no exemplo dele), uma para enviar emails e outra para gerar SMS/paging, mas eu prefiro criar só uma e deixar a decisão de enviar email ou um pager/SMS baseada no outro parâmetro do ALARMPROGRAM, a severidade.
Na verdade, eu habitualmente utilizo uma versão alterada do ALARMPROGRAM onde eu posso definir que todos os eventos com uma dada severidade enviam um SMS e abaixo disso apenas enviam um email, ou alternativamente definir um conjunto de classes que enviam sempre ou emails ou SMS conforme a gravidade.

Em qualquer caso, configure e teste o seu script de ALARMPROGRAM para receber uma nova classe e agir em conformidade com as suas necessidades. A vantagem de utilizar o script de ALARMPROGRAM é que isto faz com que este seja o único sitío que terá de mexer caso necessite de alterar algum email ou endereço de paging ou número de SMS. Uma vez configurado irá trabalhar perfeitamente para si e será re-utilizável para qualquer tarefa de monitorização.

Open Admin Tool a funcionar

Como se verá mais adiante esta tarefa irá gerar alertas na consola do OAT. Assim terá alguma coisa para mostrar à sua chefia. Habitualmente gostam de ver gráficos agradáveis à vista.... Para além disso, e do ponto de vista prático, o OAT facilitará o agendamento e configuração da tarefa (incluindo os seus parâmetros). Falarei disto mais adiante, até porque tenho uma queixa relativamente ao OAT :)


O scheduler da base de dados activo

Como já foi referido, esta ferramenta de monitorização será implementada como uma tarefa no scheduler da base de dados (introduzido na versão 11). Portanto isto é um requisito directo.

Um procedimento ou função para chamar o script ALARMPROGRAM

Um dos requisitos, se queremos integrar a tarefa com o script de ALARMPROGRAM é ter um procedimento que possa chamar o referido script. Este procedimento irá basicamente receber parâmetros (semelhantes aos do ALARMPROGRAM), e construir um comando de sistema operativo que será depois executado com uma chamada à instrução SYSTEM(). O caminho do ALARMPROGRAM será obtido dinamicamente na base de dados sysmaster. Desta forma não terá de alterar o procedimento, caso necessite de alterar a localização do script no sistema de ficheiros. O código para este procedimento pode ser encontrado na Listagem 1) no final deste artigo. Este procedimento irá ser chamado em vários pontos da nossa tarefa


A tarefa propriamente dita: Descrição e instalação

A tarefa de monitorização é implementada como um procedimento em linguagem SPL. O código da mesma pode ser obtido na listagem 2 no final deste artigo. Vamos analisá-lo quase linha a linha.


  • Linhas 1 e 2 são apenas as instruções de DROP/CREATE. Repare-se que o procedimento recebe dois argumentos que são realmente uma grande ajuda, como veremos mais tarde:
    task_id é o id na tabela ph_task. É único para cada tareda e permite-nos referenciar outras tabelas na base de dados sysadmin que sustenta o scheduler e muitas funcionaliades do OAT
    v_id é o número da execução desta tarefa. Irá mudar (incrementalmente) cada vez que a tarefa é executada
  • As linhas seguintes, até à 19 são definições de variáveis. Não as irei explicar isoladamente pois serão referidas nos comentários abaixo
  • Linhas 20 a 25 referem-se a instruçoes de debug. Remova os comentários das linhas 23 e 24 para obter um trace da execução do procedimento, criado em /tmp (a localização pode obviamente ser mudada)
  • As linhas 29 a 31 são muito importantes. Os valores nelas definidos são o último recurso utilizado pelo procedimento se todos os outros parâmetros de configuração não forem definidos. Os valores aqui definidos por omissão são:
    default yellow threshold (90): Isto representa a percentagem de utilização de um qualquer dbspace, acima do qual será emitido um alerta amarelo (severidade 3 no ALARMPROGRAM)
    default red threshold (95): Isto representa a percentagem de utilização de um qualquer dbspace, acima do qual será emitido um alerta vermelho (severidade 4 no ALARMPROGRAM)
    number of alarms (3): Isto representa o número de alarmes a enviar. Um valor de zero sinaliza que devem ser enviados alarmes até que a situação seja resolvida

    Como veremos a seguir, estes valores podem ser sobrepostos por valores atribuídos a parâmetros de configuração da tarefa, e os limites vermelho e amarelo podem ser definidos por dbspace.
    Os valores acima só serão utilizados se os outros, mais específicos não forem definidos. E claro que estes valores podem ser alterados no código do procedimento antes de fazer a instalação no seu ambiente, de forma a adaptá-los às suas necessidades e preferências.
  • Linha 33 é muito importante dado que define a class passada ao ALARMPROGRAM referente a falta de espaço livre num dbspace. Isto deve ser ajustado ao valor da classe adicionada ao ALARMPROGRAM. Eu utilizo valores na casa dos 900 para as minhas extensões "pessoais", de forma a que não venham a sobrepor-se com classes presentes no ALARMPROGRAM, adicionadas pela IBM no futuro (não sabemos quantas poderão ser adicionadas, mas começar nos 900 dá uma margem razoável)
  • Linhas 35 a 93. Aqui tentamos ler os valores configurados para os parâmetros de funcionamento acima. Estes valores são items de configuração das tarefas. Infelizmente a versão actual do OAT não permite configurá-los via interface gráfica, ou melhor, não permite criá-los. Teremos de os inserir usando SQL e depois então podemos manipulá-los via OAT. Gostaria que o processo de criação das tarefas no OAT permitisse introduzir estes parâmetros. Mas de momento (versão 2.28) isto não está disponível e portanto teremos de os inserir via SQL. Como o fazer? Estes valores são guardados na tabela ph_threshold que contém os seguintes campos:
    name: Este é o nome do parâmetro. No nosso caso, temos os seguintes: DEFAULT NUM ALARMS, DBSPACE YELLOW DEFAULT, DBSPACE RED DEFAULT e depois podemos inserir qualquer um na forma DBSPACE YELLOW dbspace_name e DBSPACE RED dbspace_name. Penso que os nomes já explicam o significado. A ideia é que se quisermos ter limites "amarelos" e "vermelhos" para dbspaces específicos temos de inserir um parâmetro com o nome DBSPACE RED/YELLOW dbspace_name na tabela ph_thresholds. Se não existir um valor específico para um determinado dbspace o procedimento irá usar o valor indicado pelo parâmetro DBSPACE RED/YELLOW DEFAULT. Se estes também não estiverem definidos, irá usar os valores definidos nas linhas 29 a 31
    task_name: O nome da tarefa na tabela ph_task. Este valor tem de se igual ao nome que dermos a esta tarefa, e esse será o que dermos na criação do agendamento para a mesma. Neste artigo usarei "IXMon Check Space". Pode usar o que desejar, desde que mantenha a coerencia
    value: O valor do limite. Este valor será usado pela tarefa. No nosso caso, os parâmetros DBSPACE RED/YELLOW * serão representados em percentagem (1-100).
    value_type: O tipo de dados do limite (STRING ou NUMERIC). No nosso caso usaremos NUMERIC. Investigando um pouco foi possível perceber que podemos usar NUMERIC(x,y) para valores fraccionados. Não testei, mas deverá funcionar, caso isso faça sentido para as suas necessidades.
    description: Uma descrição do que o limite controla. Isto será utilizado pela interface gráfice do OAT, caso posteriormente queira editar os valores pelo OAT.

    Para dar alguns exemplos apresento de seguida as instruções para criar os parâmetros cuja definição também existe no código (número de alarmes, limites genéricos amarelo e vermelho). Usarei os mesmo valores:
    INSERT INTO ph_threshold ( name, task_name, value, value_type, description)
    VALUES ( 'DEFAULT NUM ALARMS', 'IXMon Check Space', '3', 'NUMERIC', 'Numero de alarmes a enviar');
    INSERT INTO ph_threshold ( name, task_name, value, value_type, description)
    VALUES ( 'DBSPACE YELLOW DEFAULT', 'IXMon Check Space', '90', 'NUMERIC', 'Limite amarelo generico. Sera aplicado a qualquer dbspace que nao tenha um parametro especifico');
    INSERT INTO ph_threshold ( name, task_name, value, value_type, description)
    VALUES ( 'DBSPACE RED DEFAULT', 'IXMon Check Space', '95', 'NUMERIC', 'Limite vermelho generico. Sera aplicado a qualquer dbspace que nao tenha um parametro especifico');


    E por exemplo, se tiver um dbspace com o nome
    llogs_dbs, dedicato aos logical logs, que esteja practicamente cheio e que portanto não fará sentido monitorizar poderia adicionar:


    INSERT INTO ph_threshold ( name, task_name, value, value_type, description)
    VALUES ( 'DEFAULT YELLOW llogs_dbs', 'IXMon Check Space', '100', 'NUMERIC', 'Faz com que o llogs_dbs passe todos os teses...');
    INSERT INTO ph_threshold ( name, task_name, value, value_type, description)
    VALUES ( 'DEFAULT RED llogs_dbs', 'IXMon Check Space', '100', 'NUMERIC', 'Faz com que o llogs_dbs passe todos os teses...');


  • Linha 97 cria um ciclo FOREACH. É baseado na query das linhas seguintes a qual verifica o espaço utilizado em cada dbspace do sistema.
  • Linhas 98 a 111. Esta é a query referida acima. Algumas partes dela podem não ser necessárias para este efeito, mas foi retirada de outro script... Não se preocupe, deve funcionar. Dá o número de páginas e o número de páginas livres em todos os chunks do dbspace.
    Note que esta tarefa é baseada em percentagem de utilização. Poderia ser melhorada para lidar com outros tipos de parâmetros como os GB alocados, os GB livres etc. Por agora mantive-a simples.
  • Linhas 114 a 153 são usadas para tentar obter limites específicos para o dbspace que está a ser processado. Se não forem encontrados na tabela ph_threshold os limites genéricos serão utilizados
  • Linhas 154 a 172. Aqui calculamos a percentagem de espaço utilizado e verificamos se excede o limite amarelo ou vermelho. Se tal acontecer inicializamos a variável com a cor do alerta e a mensagem de alerta. Se estivermos abaixo do limite amarelo então deixamos a variável da cor a NULL
  • Linhas 175 a 200. Se a utilização actual estiver abaixo do limite inferior (amarelo), procuramos um alerta já inserido na tabela ph_alert para este dbspace com o state igual a "NEW". Se encontrarmos alteramo-lo, mudando o estado para "ADDRESSED". Isto pode acontecer se depois de um alerta alguém apagar uma tabela por exemplo. Nesta situação não estou a chamar o ALARMPROGRAM, mas poderia fazer sentido chamá-lo com uma mensagem do tipo: "O alarme anterior para o dbspace dbspace_name foi cancelado porque estamos agora abaixo do limite definido"
  • Da 204 até ao final, código que trata as situações em que excedemos um dos limites.... Assim... Primeiro pesquisamos na ph_alert para ver se temos um alarme para este dbspace no estado "NEW". Se não tivermos (223 - 239) inserimo-lo e chamamos o ALARMPROGRAM usando o procedimento referido acima. Se já tivermos um alarme verificamos se é da mesma cor. Se não for (244 - 252), fazemos um UPDATE a dois campos:
    alert_task_seq: Fazemos isto para reposicionar o contador do alarme.
    alert_color: Alteramos o código de cor do alarm (para utilização na interface do OAT). Note que nesta altura podemos ter um alarme vermelho, com um texto de mensagem referente a um amarelo. Preferi manter assim, para mostrar que houve uma alteração entre a situação original e a actual. No entanto o alarme que é enviado ao ALARMPROGRAM tem a mensagem correspondente ao alarme vermelho. Só no OAT se verá a diferença. Se o alarme tiver a mesma cor, verificamos o campo alert_task_seq e comparamo-lo com o nósso número de execução da tarefa (dado como parâmetro na chamada do procedimento) e decidimos, baseado no número de alarmes se devemos ou não chamar o ALARMPROGRAM.
Finalmente, como é que agendamos a tarefa? Podemos fazê-lo via interface do OAT. ou se preferir podemos inserir directamente o registo na tabela ph_task:



INSERT INTO ph_task
(
tk_id, tk_name, tk_description, tk_type, tk_dbs,
tk_execute, tk_start_time, tk_frequency,
k_monday, tk_tuesday, tk_wednesday, tk_thursday,
tk_friday, tk_saturday, tk_sunday,
tk_group, tk_enable, tk_priority
)
VALUES
(
0, 'IXMon Check Space', 'Check dbspace free space', 'TASK', 'sysadmin',
'ixmon_check_space', '00:00:00', '0 00:30:00',
't', 't', 't', 't', 't', 't', 't',
'USER','t',0
)



Atualização [ 20 Ago 2010]:

Tinha-me esquecido de um bloco condicional (IF) em volta do UPDATE que altera o estado de um alerta já existente para 'ADDRESSED' (linhas 195-200)
Como estava, o UPDATE era sempre feito mesmo quando não tinhamos encontrado um alerta. Isto não seria um erro grave, mas caso também queira chamar
o ALARMPROGRAM quando as condições do alarme são reveridas então necessitamos deste ID, ou a tarefa irá enviar alarme para cada dbspace que esteja dentro dos limites
Peço desculpa pela confusão.... Portanto adicionei o IF da linha 194 e o END IF da linha 201.




Listing 1:



DROP PROCEDURE call_alarmprogram;
CREATE PROCEDURE call_alarmprogram(
v_severity smallint,
v_class smallint,
v_class_msg varchar(255) ,
v_specific varchar(255) ,
v_see_also varchar(255)
)


-- severity: Category of event
-- class-id: Class identifier
-- class-msg: string containing text of message
-- specific-msg: string containing specific information
-- see-also: path to a see-also file

DEFINE v_command CHAR(2000);
DEFINE v_alarmprogram VARCHAR(255);

--SET DEBUG FILE TO '/tmp/call_alarmprogram.dbg' WITH APPEND;
--TRACE ON;

SELECT
cf_effective
INTO
v_alarmprogram
FROM
sysmaster:sysconfig
WHERE
cf_name = "ALARMPROGRAM";

LET v_command = TRIM(v_alarmprogram) || " " || v_severity || " " || v_class || " '" || v_class_msg || "' '" || NVL(v_specific,v_class_msg) || "' '" || NVL(v_see_also,' ') || "'";
SYSTEM v_command;
END PROCEDURE;


Listing 2:



1 DROP FUNCTION ixmon_check_space;
2 CREATE FUNCTION "informix".ixmon_check_space(task_id INTEGER, v_id INTEGER) RETURNING INTEGER
3
4 DEFINE v_default_num_alarms, v_num_alarms SMALLINT;
5 DEFINE v_default_yellow_threshold, v_default_red_threshold SMALLINT;
6 DEFINE v_generic_yellow_threshold, v_generic_red_threshold SMALLINT;
7 DEFINE v_dbs_yellow_threshold, v_dbs_red_threshold SMALLINT;
8 DEFINE v_name LIKE ph_threshold.name;
9 DEFINE v_dbsnum INTEGER;
10 DEFINE v_dbs_name CHAR(128);
11 DEFINE v_pagesize, v_is_blobspace, v_is_sbspace, v_is_temp SMALLINT;
12 DEFINE v_size, v_free BIGINT;
13 DEFINE v_used DECIMAL(4,2);
14 DEFINE v_alert_id LIKE ph_alert.id;
15 DEFINE v_alert_task_seq LIKE ph_alert.alert_task_seq;
16 DEFINE v_alert_color,v_current_alert_color CHAR(6);
17 DEFINE v_message VARCHAR(254,0);
18
19 DEFINE v_severity, v_class SMALLINT;
20 ---------------------------------------------------------------------------
21 -- Uncomment to activate debug
22 ---------------------------------------------------------------------------
23 --SET DEBUG FILE TO '/tmp/ixmon_check_space.dbg' WITH APPEND;
24 --TRACE ON;
25
26 ---------------------------------------------------------------------------
27 -- Default values if nothing is configured in ph_threshold table
28 ---------------------------------------------------------------------------
29 LET v_default_yellow_threshold=90;
30 LET v_default_red_threshold=95;
31 LET v_default_num_alarms=3;
32
33 LET v_class = 908;
34
35 ---------------------------------------------------------------------------
36 -- Get the number of times to call the alarm...
37 ---------------------------------------------------------------------------
38
39 LET v_num_alarms=NULL;
40
41 SELECT
42 value
43 INTO
44 v_num_alarms
45 FROM
46 ph_threshold
47 WHERE
48 task_name = 'IXMon Check Space' AND
49 name = 'DEFAULT NUM ALARMS';
50
51 IF v_num_alarms IS NULL
52 THEN
53 LET v_num_alarms=v_default_num_alarms;
54 END IF;
55
56 ---------------------------------------------------------------------------
57 -- Get the defaults configured in the ph_threshold table
58 ---------------------------------------------------------------------------
59 LET v_generic_yellow_threshold=NULL;
60 LET v_generic_red_threshold=NULL;
61
62 SELECT
63 value
64 INTO
65 v_generic_yellow_threshold
66 FROM
67 ph_threshold
68 WHERE
69 task_name = 'IXMon Check Space' AND
70 name = 'DBSPACE YELLOW DEFAULT';
71
72 IF v_generic_yellow_threshold IS NULL
73 THEN
74 LET v_generic_yellow_threshold=v_default_yellow_threshold;
75 END IF;
76
77
78
79 SELECT
80 value
81 INTO
82 v_generic_red_threshold
83 FROM
84 ph_threshold
85 WHERE
86 task_name = 'IXMon Check Space' AND
87 name = 'DBSPACE RED DEFAULT';
88
89 IF v_generic_red_threshold IS NULL
90 THEN
91 LET v_generic_red_threshold=v_default_red_threshold;
92 END IF;
93
94 ---------------------------------------------------------------------------
95 -- Foreach dbspace....
96 ---------------------------------------------------------------------------
97 FOREACH
98 SELECT
99 d.dbsnum, d.name, d.pagesize, d.is_blobspace, d.is_sbspace, d.is_temp,
100 SUM(c.chksize), SUM(c.nfree)
101 INTO
102 v_dbsnum, v_dbs_name, v_pagesize, v_is_blobspace, v_is_sbspace, v_is_temp,
103 v_size, v_free
104 FROM
105 sysmaster:sysdbspaces d, sysmaster:syschunks c
106 WHERE
107 d.dbsnum = c.dbsnum
108
109
110 GROUP BY 1, 2, 3, 4, 5, 6
111 ORDER BY 1
112
113
114 ---------------------------------------------------------------------------
115 -- Get specific dbspace red threshold if available....
116 ---------------------------------------------------------------------------
117 LET v_name = 'DBSPACE RED ' || TRIM(v_dbs_name);
118
119 SELECT
120 value
121 INTO
122 v_dbs_red_threshold
123 FROM
124 ph_threshold
125 WHERE
126 task_name = 'IXMon Check Space' AND
127 name = v_name;
128
129 IF v_dbs_red_threshold IS NULL
130 THEN
131 LET v_dbs_red_threshold = v_generic_red_threshold;
132 END IF;
133
134 ---------------------------------------------------------------------------
135 -- Get specific dbspace yellow threshold if available....
136 ---------------------------------------------------------------------------
137 LET v_name = 'DBSPACE YELLOW ' || TRIM(v_dbs_name);
138
139 SELECT
140 value
141 INTO
142 v_dbs_yellow_threshold
143 FROM
144 ph_threshold
145 WHERE
146 task_name = 'IXMon Check Space' AND
147 name = v_name;
148
149 IF v_dbs_yellow_threshold IS NULL
150 THEN
151 LET v_dbs_yellow_threshold = v_generic_yellow_threshold;
152 END IF;
153
154 ---------------------------------------------------------------------------
155 -- Calculate used percentage and act accordingly...
156 ---------------------------------------------------------------------------
157 LET v_used = ROUND( ((v_size - v_free) / v_size) * 100,2);
158 IF v_used > v_dbs_red_threshold
159 THEN
160 LET v_alert_color = 'RED';
161 LET v_message ='DBSPACE ' || TRIM(v_dbs_name) || ' exceed the RED threshold (' ||v_dbs_red_threshold||'). Currently using ' || v_used ;
162 LET v_severity = 4;
163 ELSE
164 IF v_used > v_dbs_yellow_threshold
165 THEN
166 LET v_alert_color = 'YELLOW';
167 LET v_message ='DBSPACE ' || TRIM(v_dbs_name) || ' exceed the YELLOW threshold (' ||v_dbs_yellow_threshold||'). Currently using ' || v_used ;
168 LET v_severity = 3;
169 ELSE
170 LET v_alert_color = NULL;
171 END IF
172 END IF
173
174
175 IF v_alert_color IS NULL
176 THEN
177 ---------------------------------------------------------------------------
178 -- The used space is lower than any of the thresholds...
179 -- check to see if there is an already inserted alarm
180 -- If so... clear it...
181 ---------------------------------------------------------------------------
182 LET v_alert_id = NULL;
183
184 SELECT
185 p.id, p.alert_task_seq, p.alert_color
186 INTO
187 v_alert_id, v_alert_task_seq, v_current_alert_color
188 FROM
189 ph_alert p
190 WHERE
191 p.alert_task_id = task_id
192 AND p.alert_object_name = v_dbs_name
193 AND p.alert_state = "NEW";
194 IF v_alert_id IS NOT NULL
195 UPDATE
196 ph_alert
197 SET
198 alert_state = 'ADDRESSED'
199 WHERE
200 ph_alert.id = v_alert_id;
201 END IF;
202 ELSE
203
204 ---------------------------------------------------------------------------
205 -- The used space is bigger than one of the thresholds...
206 -- Check to see if we already have an alert in the ph_alert table in the
207 -- state NEW ...
208 ---------------------------------------------------------------------------
209
210 LET v_alert_id = NULL;
211
212 SELECT
213 p.id, p.alert_task_seq, p.alert_color
214 INTO
215 v_alert_id, v_alert_task_seq, v_current_alert_color
216 FROM
217 ph_alert p
218 WHERE
219 p.alert_task_id = task_id
220 AND p.alert_object_name = v_dbs_name
221 AND p.alert_state = "NEW";
222
223 IF v_alert_id IS NULL
224 THEN
225 ---------------------------------------------------------------------------
226 -- There is no alarm... or the alarm changed from NEW
227 ---------------------------------------------------------------------------
228
229 INSERT INTO
230 ph_alert (id, alert_task_id, alert_task_seq, alert_type, alert_color, alert_time,
231 alert_state, alert_state_changed, alert_object_type, alert_object_name, alert_message,
232 alert_action_dbs)
233 VALUES(
234 0, task_id, v_id, 'WARNING', v_alert_color, CURRENT YEAR TO SECOND,
235 'NEW', CURRENT YEAR TO SECOND,'DBSPACE', v_dbs_name, v_message, 'sysadmin');
236
237 EXECUTE PROCEDURE call_alarmprogram(v_severity, v_class, 'DBSPACE used space too high',v_message,NULL);
238
239 ELSE
240 ---------------------------------------------------------------------------
241 -- There is an alarm...
242 -- Need to check if it's still the same color...
243 ---------------------------------------------------------------------------
244 IF v_current_alert_color != v_alert_color
245 THEN
246 ---------------------------------------------------------------------------
247 -- Change the color... And reset the seq to reactivate the couter...
248 ---------------------------------------------------------------------------
249 UPDATE ph_alert
250 SET (alert_task_seq, alert_color) = (v_id,v_alert_color)
251 WHERE ph_alert.id = v_alert_id;
252 EXECUTE PROCEDURE call_alarmprogram(v_severity, v_class, 'DBSPACE used space too high',v_message,NULL);
253 ELSE
254 IF (v_id < v_alert_task_seq + v_num_alarms) OR v_num_alarms = 0
255 THEN
256 EXECUTE PROCEDURE call_alarmprogram(v_severity, v_class, 'DBSPACE used space too high',v_message,NULL);
257 END IF;
258 END IF;
259 END IF;
260 END IF;
261 END FOREACH
262
263 END FUNCTION;

Tuesday, August 28, 2012

Informix 11.70.xC2: It's out!

This article is written in English and Portuguese
Este artigo está escrito em Inglês e Português

English Version:

It's been too long since my last post. The reason is the usual lack of time. Sorry for that...
This is just a small post to let you know that Informix version 11.70.xC2 is being made available. It's already possible to get if from the Fix Central site (link on the right). The Information Center documentation site is still not updated. But a quick look into the release notes shows some interesting stuff:
  • Installation without root privileges
    This makes it possible to install and use Informix without root privileges. But due to the Unix/Linux nature, some features may not be available. This was a request from some embedded solutions providers. So it's another feature that helps make Informix the right choice for those environments. I believe we'll see more developments in the usage without root privileges in the future.
  • More SQL Admin API commands
    This time will see things like CREATE/DROP DATABASE and ONTAPE/ONBAR/ONSMSYNC commands. This is great since you can trigger your backups as tasks. Something that we're missing.
  • More improvements in the BTS text search datablade. IBM continues to improve this datablade which it free of charges
  • Table and column ALIASES in DML instructions (SELECT, DELETE and UPDATE)
    The ALIAS can now be used in GROUP BY clauses. I like this one. We could use numbers, but if you change your projection list you also need to change the GROUP BY clause.
  • Case insensitive searches
    This was also a frequently asked for feature. It applies only to NCHAR and NVARCHAR fields and you need to specify it in the CREATE DATABASE statement
  • OAT improvements
    As usual, when we see engine improvements we also see them in OAT. This time, a new area lets you manage your backups. Other features include the ability to uninstall a plug-in (something I also missed), ability to create reports based on historical data, improvements in the schema manager plugin-in and a few more
  • Ability to configure the number of file descriptor servers
    This is an intriguing feature related to a nasty problem that affects Informix instances with very intensive usage (I'm talking about thousands of concurrent connections, and a very high rate of new connections per second - typical values lay in the vicinity of more than 2000 concurrent sessions and/or more than 15 new connections per second, but it really depends on the environment). This issue is worth a dedicated article, and tech support usually knows it by "nsf.lock issue". If you never heard about it, it's because you don't suffer from it. In any case, this feature is in fact present in several older versions (later v10 fixpacks and 11.50). Unfortunately it was not properly documented. Also note that v11.7 has some structural changes that should eliminate this problem. The feature is translated into a new parameter called NUMFDSERVERS. Classical versions (pre v10.??) used just one. Somewhere in the v10 family it was decided that more was better, but sometimes it isn't due to other points of contention (eliminated in v11.7). So now you can decide how many to use.
  • Informix Warehouse Accelerator
    This is a new product that uses new technology. It is composed of a new in-memory based query engine, and a tool you use to map your OLTP data into that new system. Then, when you send DSS like queries to the OLTP engine, it will decide if the "partner" system can handle them. If it does the query is routed transparently and the results sent back. If it doesn't than the OLTP will resolve the queries. The advantage is that you get much (really!) faster query times on the queries routed to the new system. There was a preview of these technology on IIUG conference last year and the results were impressive. Please be alert, because there will be some buzz around this (the same technology is already available on DB2 for z/OS)
In short that's it. And there as with any other fixpack there are some bug fixes.


Versão Portuguesa:


Passou muito tempo desde o último artigo. A razão é a habitual falta de tempo. As minhas desculpas...
Este artigo serve apenas para dar conta de que a versão 11.7.xC2 do Informix está a ser disponibilizada. Já é possível obtê-la do site Fix Central (ligação à direita). A documentação no Information Center ainda estará a ser actualizada. Mas uma pequena espreitadela nas release notes mostra algumas coisas interessantes:
  • Instalação sem privilégios de root.
    Isto torna possível instalar e utilizar o Informix sem privilégios de root. Mas dada a natureza dos sistemas operativos Unix/Linux, algumas funcionalidades poderão não estar disponíveis. Isto foi um pedido de alguns fornecedores de soluções embebidas. Por isso é mais uma funcionalidade que ajuda o Informix a ser a escolha acertada para este tipo de ambientes. Acredito que iremos ver mais desenvolvimentos relativos à utilização sem root no futuro
  • Mais comandos da API de administração SQL
    Desta vez vemos comandos como CREATE/DROP DATABASE e ONTAPE/ONBAR/ONSMSYNC. Isto é óptimo pois passamos a poder despoletar backups como tarefas. Algo que já se sentia falta
  • Mais melhorias no datablade de pesquisa de texto livre (BTS)
    A IBM continua a melhorar este datablade que é distribuído sem custos com o produto
  • ALIAS em tabelas e colunas nas instruções de DML ((SELECT, DELETE and UPDATE)
    Os ALIAS podem agora ser usados nas cláusulas de GROUP BY. Pessoalmente agrada-me bastante. Já podíamos usar números, mas se mudássemos a projection list teríamos também de arranjar a cláusula GROUP BY
  • Pesquisas por caracteres não sensíveis a maiúsculas ou minúsculas
    Esta funcionalidade fazia parte da lista com mais pedidos. Só se aplica a colunas NCHAR e NVARCHAR e tem de ser especificada na criação da base de dados (instrução CREATE DATABASE)
  • Melhorias no OAT
    Como vem sendo hábito, sempre que temos melhorias no motor também as vemos no OAT. Desta vez, uma nova área permite gerir os backups. Outras novidades inclúem a possibilidade de desinstalar plug-ins (algo que sentia falta), criação de relatórios baseados em dados de histórico, melhorias no plug-in de gestão de schema e mais alguns
  • Possibilidade de configurar o número de servidores de file descriptors.
    Isto é uma funcionalidade algo intrigante, relacionada com um problema complexo que afecta instâncias Informix com uma utilização muito intensiva (estou a falar de milhares de sessões concorrentes e uma taxa muito alta de novas sessões por segundo - valores tipicos situam-se perto de mais de 2000 sessões concorrentes e/ou mais de 15 novas sessões por segundo, mas dependerá sempre de cada ambiente)
    Este assunto mereceria por si só um artigo, mas o suporte técnico reconhece-o por "problema do nsf.lock". Se nunca ouviu falar nele é porque nunca sofreu com ele. Em qualquer caso, esta funcionalidade está de facto presente em várias versões já antigas (últimos fixpacks da versão 10 e fixpacks da versão 11.50). Infelizmente não estava devidamente documentadas. Note-se também que a versão 11.7 tem algumas modificações estruturuais que deverão eliminar este problema. A funcionalidade traduz-se num novo parâmetro chamado NUMFDSERVERS. Versões antigas (pre v10.??) usavam apenas um servidor de file descriptors. Num determinado fixpack da versão 10 considerou-se que mais era melhora, mas em alguns casos não é, devido a outros pontos de contenção (eliminados na versão 11.7). Assim, agora podemos decidir e ajustar quantos queremos
  • Informix Warehouse Accelerator
    Isto é um novo produto que utiliza tecnologia nova. É composto por um motor de queries, baseado em memória, e uma ferramenta que pode usar-se para mapear alguns dados do sistema OLTP neste novo sistema. Depois, quando enviados uma query do tipo DSS ao motor OLTP, ele decide se o novo sistema associado pode resolver a query. Se sim, a query é enviada transparentemente ao novo sistema, e os resultados são enviados de volta. Se a query não puder ser processada pelo sistema "emparceirado", então o sistema OLTP irá resolvê-la. A vantagem é que obteremos muito (mesmo muito!) melhores tempos de execução nas querys enviadas ao novo sistema. Houve uma antevisão do sistema na última conferência do IIUG e os resultados eram realmente impressionantes. Mantenha-se alerta, pois isto irá certamente dar que falar nos próximos tempos (a mesma tecnologia já existe para DB2 em z/OS)
Em resumo é isto. E como em qualquer outro fixpack contém igualmente um número de correcções.

Monday, August 27, 2012

Panther: Extending extents / Estendendo os extents

This article is written in English and Portuguese
Este artigo está escrito em Inglês e Português

English version:

Back to Panther... Although I'm not in the video on the right, I do love Informix. That doesn't mean I ignore some issues it has (or had in this particular case). One thing that always worries an Informix DBA is the number of extents in his tables. Why? Because it used to have a maximum amount, and because that maximum was pretty low (if compared with other databases). But what is an extent? In short an extent is a sequence of contiguous pages (or blocks) that belong to a specific table or table partition. A partition (a table has one or more partitions) has one or more extents.
Before I go on, and to give you some comparison I'd like to tell you about some feedback I had over the years from a DBA (mostly Oracle, but who also managed an Informix instance):
  • A few years ago he spent lots of time running processes to reduce the number of extents in a competitor database that had reach an incredible number of extents (around hundreds of thousands). This was caused by real large tables and real badly defined storage allocation
  • Recently I informed the same customer that Informix was eliminating the extent limits and the same guy told me that he was afraid that it could lead to situations as above. He added, and I quote, "I've always admired the way Informix deals with extents"
So, if a customer DBA is telling that he admires the way we used to handle extents, and he's afraid of this latest change, why am I complaining about the past? As in many other situations, things aren't exactly black and white... Let's see what Informix have done well since ever:

  1. After 16 allocations of new extents Informix automatically doubles the size of the next extent for the table. This decreases the number of times it will try to allocate a new extent. So, using only this rule (which is not correct as we shall see) if you create a table with a next size of 16K, you would reach 4GB with around 225 extents.
  2. If Informix can allocate a new extent contiguous to an already existing one (from the same table of course) than it will not create a new one, but instead it will extend the one that already exists (so it does not increase the number of extents). This is one reason why rule number one may not be seen in practice. In other words, it's more than probable that you can reach 4GB with less than 225 extents.
  3. In version 11.50 if I'm correct, a fix was implemented to prevent excessive extent doubling (rule 1). If the next extent size is X and the dbspace only has a maximum of Y (Y < X) informix will allocate Y and will not raise any error.
    If this happens many times, we could end up having a number of allocated pages relatively small, but a next extent size too big. There's a real problem in this: If in these circumstances we create another chunk in the same dbspace, and after that our table requires another extent, the engine could reserve a large part of the new (and possibly still empty) chunk to our table. This can be much more than the size already allocated to the table. To avoid this, extent doubling will only happen when there is a reasonable relation between the new calculated next extent size and the space effectively allocated to the table.
  4. Extent description in Informix have never been stored in the database catalog. This leads to simpler and efficient space management. Compared to other databases that used to do the management in the catalog, they tend to hit issues in the SQL layer and at the same time these were slower. One of our competitors changed that in their later versions, and DBAs have seen improvement with that (but they had to convert). Informix always worked the better way...
So, these are the good points. Again, why was I complaining? Simply because although Informix has done a pretty good job in preventing the number of extents to grow too much, we had a very low limit for the number of extents. In platforms with a system page size of 2K this was around 220-240 extents (max), and for 4K platforms is was around the double of that (440-480). With version 10 we started to be able to have greater page sizes, and that increases the maximum number of extents per partition.
Why didn't we have a fix limit and why was it different in several platforms? In order to explain that we must dive a bit deeper in the structure of a dbspace and tables. Each partition in Informix has a partition header. Each partition header is stored in exactly one Informix page. There is a special partition in every dbspace (tablespace tablespace) that holds every partition headers from that dbspace. This special partition starts in a specific page but then, it can contain more than one extent.
Also important to understand this is the notion of slot. Most Informix pages contain several slots. For a data page, a slot contains a row (in the simplest cases). A partition header is a page that contains 5 slots:
  1. Slot 1
    This contains the partition structure (things like creation date, partition flags, maximum row size, number of special columns - VARCHAR and BLOB -, number of keys - if it's an index or has index pages -, number of extents and a lot of other stuff. If you want to see all the details check the sysptnhdr table in $INFORMIXDIR/etc/sysmaster.sql. It's basically an SQL interface for the partition headers in the instance.
    In version 11.50 this slot should occupy 100 bytes. Previous versions can have less (no serial 8, and bigserial)
  2. Slot 2
    Contains the database name, the partition owner, the table name and the NLS collation sequence
  3. Slot 3
    Contains details about the special columns. If there are no special columns this slot will be empty
  4. Slot 4
    Contains the description for each key (if it's an index or a mix). Starting with version 9.40, by default the indexes are stored in their own partitions. This was not the case in previous versions. A single partition could contain index pages interleaved with data pages.
    Currently, by default, a partition used for data should not have any key, so this slot will be empty
  5. Slot 5
    Finally, this is the slot that contains the list of extents.
Now we know the list of extents must be stored in the partition header. And the partition header has 5 slots, and the size of first four may vary. This means that the free space for slot 5 (extent list) is variable. These are the reasons why we had a limit and why that limit was not fixed. It would vary with the table structure for example. And naturally it would vary with the page size.
A table that reached it's maximum number of extents was a very real and serious problem in Informix. If you reach the table limit for number of extents and all your table's data pages are full, the engine would need to allocate one more extent in order to complete new INSERTs. But for that it would require some free space in the partition header. If there was no space left, any INSERT would fail with error -136:

-136 ISAM error: no more extents.

After hitting this nasty situation there were several ways to solve it, but all of them would need temporary table unavailability, which in our days is rare... We tend to use 24x7 systems. Even systems that have a maintenance window would suffer with this, because most of the time the problem was noticed during "regular" hours...

So, I've been talking in the past... This used to be a problem. Why isn't it a problem anymore? Because Panther (v11.7) introduced two great features:
  1. The first one is that it is able to automatically extend the partition header when slot 5 (the extent list) becomes full. When this happens it will allocate a new page for the partition header that will be used for the extent list. So you should not see error -136 caused by reaching the extent limit. At first you may think like my customer DBA: "wow! Isn't that dangerous? Will I get tables/partitions with tens of thousands of extents?". The answer is simple. You won't get that high number of extents because all the nice features that were always there (automatic extent concatenation, extent doubling...) are still there. This will just avoid the critical situation where the use of the table would become impossible (new INSERTs). And naturally it doesn't mean that you should not care about the number of extents. For performance reasons it's better to keep them low
  2. The second great feature is an online table defragmenter. They can grow forever, but that's not good. Once you notice you have a table with too many extents you can ask the engine to defragment it. I will not dig into this simply because someone else already did it. I recommend you check the recent DeveloperWorks article entitled "Understand the Informix Server V11.7 defragmenter"

Versão Portuguesa:

De volta à Panther... Apesar de não estar no vídeo à direita, eu adoro o Informix. Isso não significa que ignore alguns problemas que ele tem (ou tinha neste caso particular). Uma coisa que preocupa qualquer DBA Informix é o número de extents das suas tabelas. Porquê? Porque esse número tinha um máximo, e porque esse máximo era bastante baixo (se comparado com outras bases de dados). Mas o que é um extent? De forma simples, um extent é uma sequência contígua de páginas (ou blocos) que pertencem a uma tabela ou partição de tabela. Uma partição (uma tabela tem uma ou mais partições) tem um ou mais extents.
Antes de continuar, e para estabelecer uma comparação, gostaria de transmitir algum feedback que ao longo de anos tive de um DBA (essencialmente Oracle, mas também geria uma instância Informix):

  • Há alguns anos atrás passou bastante tempo a executar processos para reduzir o número de extents de uma base de dados concorrente do Informix. Essa base de dados tinha tabelas que atingiram um número incrível de extents (na casa das centenas de milhar). Isto foi causado por tabelas verdadeiramente grandes e cláusulas de alocação de espaço realmente mal definidas
  • Recentemente informei esse mesmo cliente que o Informix ia eliminar o limite de extents, e a mesma pessoa disse-me que tinha receio que isso pudesse levar a situações como a de cima. Ele acrescentou, e cito: "Se há coisa que sempre admirei foi a maneira como o Informix gere os extents".
Assim sendo, se um DBA de um cliente diz que admira a maneira como geríamos os extents e ele próprio receia a eliminação de limites, porque é que eu me queixo do passado? Como em muitas outras situações, as coisas não são bem a preto e branco... Vejamos o que o Informix sempre fez bem:

  1. Após cada 16 novos extents adicionados, o Informix automaticamente duplica o tamanho do próximo extent da tabela. Isto diminui o número de vezes que tenta reservar um novo extent. Usando apenas esta regra (o que não é correcto como veremos a seguir), se criar uma tabela com o extent mínimo (16KB), a tabela pode crescer até aos 4GB com cerca de 225 extents.
  2. Se o Informix conseguir reservar um novo extent que seja contíguo a um que já esteja alocado à mesma tabela, então em vez de criar um novo, vai alargar o já existente (portanto não aumenta o número de extents). Esta é a razão porque a regra anterior pode não ser verificada na práctica. Por outras palavaras é mais que provável que consiga atingir os 4GB com menos de 225 extents.
  3. Salvo algum erro, na versão 11.50 foi introduzida uma melhoria para prevenir a duplicação excessiva do tamanho do próximo extent (regra 1). Se o tamanho do próximo extent for X, mas o dbspace só tiver um máximo de Y espaço livre contíguo (Y < X) o Informix vai criá-lo com o tamanho Y e nem se queixará de nada. Se isto acontecer muitas vezes, podemos acabar por ter um número de páginas efectivas de uma tabela ou partição relativamente pequeno e um tamanho para o próximo extent muito grande. Existe um problema real nisto: Se nessas cirunstâncias for criado um novo chunk nesse dbspace, e a tabela precisar de novo extent, pode acontecer que o motor reserve grande parte, ou mesmo a totalidade do novo chunk para a tabela (possivelmente muito mais que o tamanho já reservado até então). Para evitar isto, a duplicação do tamanho do próximo extent só acontece quando o novo tamanho tem uma relação razoável com o espaço reservado até então. Caso contrário o tamanho do próximo extent a alocar não é duplicado.
  4. A informação dos extents em Informix nunca foi guardada nas tabelas de catálogo. Isto faz com que a sua gestão seja mais simples e eficiente. Comparada com outras bases de dados que faziam a gestão no catálogo, estas tendiam a encontrar problemas e constrangimentos próprios da camada de SQL, e ao mesmo tempo eram mais lentas. Um dos concorrentes mudou isto há umas versões atrás e os seus utilizadores viram benefícios bem notórios (mas tiveram de converter). O Informix sempre trabalhou da melhor forma...
Estes são os pontos positivos. Mais uma vez, porque é que me estava a queixar? Simplesmente porque apesar de o Informix sempre ter feito um trabalho extraordinário na prevenção contra um elevado número de extents, nós tinhamos um limite, e era muito baixo. Em plataformas com um tamanho de página de sistema de 2KB este limite rondava os 220-240 extents, e em plataformas de 4KB o limite era cerca do dobro (440-480). Com a versão 10 pudemos passar a ter páginas maiores, e isso aumenta o limite.
Porque é que o limite não é fixo, e porque é diferente consoante a plataforma? Para explicar isto temos de nos debruçar de forma mais detalhada na estrutura física de um dbspace e tabela. Cada partição em Informix tem um cabeçalho. Cada cabeçalho de partição é guardado numa página Informix. Existe uma partição especial em cada dbspace (designada habitualmente por tablespace tablespace) que guarda todos os cabeçalhos das partições criadas nesse dbspace. Esta partição especial começa numa página específica do primeiro chunk do dbspace, mas pode ter mais que um extent.
Igualmente importante para compreender isto é a noção de slot. A maioria das páginas Informix estão divididas em slots. Para uma página de dados um slot contém uma linha de dados da tabela (caso mais simples). Um cabeçalho de partição é uma página que contém cinco slots:

  1. Slot 1
    Este contém a estrutura da partição (coisas como a data de criação, flags, tamanho máximo de uma linha, numéro de colunas ditas especiais - VARCHAR e BLOBs -, número de chaves - se for um indíce ou tiver páginas de indíce -, número de extents e uma série de outros detalhes. Se tiver curiosidade em saber o que lá está guardado consulte a tabela sysptnhdr na base de dados sysmaster (ou o ficheiro $INFORMIXDIR/etc/sysmaster.sql). Basicamente esta tabela é um interface SQL sobre todos os cabeçalhos de partição da instância Informix.
    Na versão 11.50 este slot ocupa 100 bytes. Versões anteriores podem ocupar menos (ausência do serial8 e bigserial)
  2. Slot 2
    Contém o nome da base de dados, dono da partição, nome da tabela e a NLS collation sequence
  3. Slot 3
    Contém detalhes sobre todas as colunas especiais. Se não existirem colunas especiais (VARCHAR e BLOB) este slot estará vazio. Se existirem, o tamanho ocupado dependerá da estrutura da tabela.
  4. Slot 4
    Contém a descrição de cada chave (se for um índice ou um mix). Desde a versão 9.40, por omissão os indíces são guardados em partição à parte. Isto não era assim em versões anteriores. Uma partição podia conter páginas de indíces e de dados.
    Actualmente, por omissão, uma partição usada para dados não deve ter nenhuma chave, e assim este slot deve estar vazio
  5. Slot 5
    Finalmente, este é o slot que contém a lista dos extents.

Agora sabemos que a lista de estents tem de ser guardada no cabeçalho da partição. E este contém cinco slots sendo que o tamanho dos primeiros quatro varia. Isto implica que o espaço livre para o slot cinco (a lista de extents) é variável. Estas são as razões porque tinhamos um limite e porque esse limite era variável. Variava por exemplo com a estrutura da tabela. E naturalmente variava com o tamanho da página.
Uma tabela que atingisse o número máximo de extents tornava-se num problema sério em Informix. Quando tal acontece, se todas as páginas de dados estiverem cheias, o motor terá de reservar um novo extent para completar novos INSERTs. Mas para isso necessitaria de espaço livre no cabeçalho da partição. Portanto, não havendo aí espaço livre todos os INSERTs falhariam com o erro -136:

-136 ISAM error: no more extents.

Depois de batermos nesta situação havia várias formas de a resolver, mas todas elas necessitavam de indisponibilidade temporária da tabela, o que nos dias que correm é um bem raro... A tendência é usarmos sistemas 24x7. Mesmo sistemas que tenham janela de manutenção sofreriam com isto, porque na maioria das vezes o problema manifestava-se durante o horário normal ou produtivo...

Bom, mas tenho estado a falar no passado.... Isto costumava ser um problema. Porque é que já não o é? Porque a versão 11.7 (Panther) introduziu duas excelentes funcionalidades:

  1. A primeira é que a partir de agora é possível estender automaticamente o cabeçalho da partição quando o slot cinco enche. Nesta situação, uma nova página é reservada para o cabeçalho da partição e a lista de extents pode crescer. Portanto não deverá voltar a ver o erro -136 causado por atingir o limite de extents. À primeira vista pode ter a mesma reacção que o DBA do meu cliente. "Epa! Mas isso não é perigoso? Vou passar a ter tabelas/partições com dezenas de milhares de extents?". A resposta é simples. Não vai atingir esses números de extents porque todas as boas características que sempre existiram (junção automática de extents, duplicação de tamanho do próximo extent...) ainda estão presentes e funcionais. Isto apenas evitará a situação crítica em que o uso da tabela se tornava impossível (para novos INSERTs). E naturalmente isto não significa que passemos a ignorar o número de extents das nossas tabelas. Por questões de desempenho é melhor mantê-los baixos.
  2. A segunda grande funcionalidade é um desfragmentador online de tabelas ou partições. O número de extents pode crescer indefinidamente, mas isso não é bom. Assim que notar que tem uma partição com um número elevado de extents pode pedir ao motor que a desfragmente. Não vou aprofundar este tema, simplemente porque já foi feito. Recomendo que consulte um artigo recente do DeveloperWorks intitulado "Understand the Informix Server V11.7 defragmenter". Infelizmente o artigo só tem versão em Inglês

Sunday, August 26, 2012

Novas edições de Informix: Saldos? [Verifique o novo artigo e nota final]

Hi. In the last IIUG conference I had the chance of talking to some Brazilian members of the Informix community and they gave me the idea that there is an high demand for Portuguese content. When I started the blog I decided to do it in English (and that was not an easy decision because I'm not that confident about my English) for two main reasons:
  • I wanted to reach a wider audience
  • I believe most Portuguese IT workers are used to read English, so it would not be hard for them to follow this (ignoring my English mistakes of course)
The last reason probably encloses two mistakes. The main one is that the Portuguese speaking audience is much bigger that Portugal (for those who don't know Portugal has around 10M people. Brazil is probably 20+ times this and then there are the African countries like Angola, Mozambique, Cabo Verde etc.). The other mistake may be that too many people in Portugal may care about this and may not want to read stuff in English. All this intro serves to say that I'll probably be doing some articles in Portuguese. I really haven't decided yet on how to do it (same article with two languages, or repeat the article. or create another blog...? For now and because I think this is a very important subject, I'll continue this article in Portguese to talk about the new Informix Editions.

----- Portuguese from here on.... -----------------------

Introdução:

Bom, para quem teve o trabalho de ler a introdução acima em Inglês por favor ignore este paràgrafo. Para os restantes basicamente a introdução serve para explicar que apesar de a lingua do blog ser o Inglês é provável que comece a publicar alguma informação em Português. A razão porque escolhi o Inglês para escrever o blog foi porque tenho a ideia que em Portugal a maioria das pessoas que trabalham em informática não se importam de ler Inglês e assim consegui uma audiência maior. Na conferência de utilizadores deste ano tive oportunidade de trocar impressões com membros Brasileiros da comunidade Informix e eles deram-me a ideia que há muita gente para quem este assunto não é indiferente e portanto existe muita gente que por um motivo ou outro preferem ou restringem-se aos conteúdos em Português. Assim, e porque o tema do último artigo é realmente muito importante, tomo-o como o ponto de partida para algumas entradas em Português no blog.

Novas edições do Informix

Como já terão tido oportunidade de ler ou ouvido comentar, a partir do dia 25 de maio de 2010 a IBM reformulou a oferta das várias edições do Informix.
Portanto algumas das edições a que estávamos habituados deixaram de estar disponíveis. Nomeadamente a Enterprise Edition e a Workgroup Edition foram descontinuadas. Como susbtituição foram introduzidas respectivamente a Ultimate Edition e a Growth Edition (ah... os nomes...). De forma muito resumida, a Ultimate Edition inclui tudo o que o Informix tem para oferecer com excepção da Storage Optimization Feature (compressão), e a Growth Edition exclui particionamento, funcionalidades de paralelismo, e compressão (inclui Enterprise Replication e clustering - até dois nós secundários em modo leitura/escrita - ) e está limitada a 4 sockets ou 16 cores e 16GB de RAM (soma do total de memória atribuída ao Informix em cada instalação).

Mas as grandes novidades são a introdução de duas novas edições: Innovator-C (disponível para todas as plataformas) e a Ultimate-C para Windows e MacOS. Mas o que têm de não diferente estas edições "-C"?:
  • Pode fazer o download, desenvolver e colocar em produção sem custos de licenciamento
  • Pode adquirir suporte
  • Apesar de terem limites nos recursos que podem utilizar, mas esses limites são razoáveis (certamente haverá opiniões contrárias)
Vamos examiná-las com mais detalhe. "-C" significa "Community". Comecemos pela Innovator-C:
  • Download livre e sem custos
  • Pode ser usada para desenvolvimento sem custos
  • Pode ser utilizada em produção
  • Está disponível para todas as plataformas suportadas pelo Informix
  • Limitada a 2GB de RAM (soma de toda a memória atribuída ao Informix por cada instalação), 1 socket ou 4 cores, sem limites de espaço usado em disco
  • Dois nós de Enterprise Replication
  • HDR (1 nó secundário em modo de leitura/escrita)
  • Funcionalidades não disponíveis: Compressão, Continuous Availability Feature ( CAF - shared disk secondaries - nós secundários com discos partilhados), particionamento, funcionalidades de paralelismo, Advanced Access Control (LBAC), Informix Warehouse e múltiplos nós secundários, encriptação de colunas, queries distríbuídas (I-Star) e outras funcionalidades (detalhes na licença)
  • Suporte opcional
E agora a Ultimate-C Edition para Windows e MacOS:
  • Download livre e sem custos
  • Pode ser usada para desenvolvimento sem custos
  • Pode ser utilizada em produção
  • Está disponível apenas para Windows e MacOS
  • Limitada a 16GB de RAM (soma de toda a memória atribuída ao Informix por cada instalação), 4 sockets ou 16 cores, sem limites de espaço usado em disco
  • Enterprise Replication totalmente funcional
  • HDR (1 nó secundário em modo de leitura/escrita)
  • Particionamento
  • Paralelismo
  • Nós secundários em modo leitura/escrita
  • Warehouse Feature (ETL)
  • Advanced Access Control (LBAC)
  • Informix Warehouse Tool (SQW)
  • Funcionalidades não disponíveis: Compressão, Continuous Availability Feature ( CAF - shared disk secondaries - nós secundários com discos partilhados)
  • Suporte opcional
NOTA: Estas edições não podem ser redistribuidas sem um acordo prévio com a IBM.

Outras edições permanecem como existiam: Developer Edition e Express Edition.
Portanto agora temos uma base de dados gratuita com algumas limitações, mas que se aplica a muitos cenários. Significará isto que a IBM perderá vendas? Não necessariamente. É claro que pode comprar-se suporte. Quem implementar soluções criticas sobre estas edições de gratuito irá provavelmente desejar ter suporte. Por outro lado isto deverá aumentar a penetração e reconhecimento do Informix no mercado. Estas edições poderão ser o par perfeito para a iniciativa de open source. Poderia falar de várias situações que levaram algumas empresas e usar mySQL ou Postgres simplesmente por causa do custo. Muitos destes cenários poderiam enquadrar-se nas possíveis utilizações destas versões. Isto torna a iniciativa de Open Source ainda mais relevante agora. As melhorias no Hibernate são um excelente sinal e depois de uma troca de impressões com um parceiro local penso que outros projectos Open Source deveriam receber atenção da iniciativa. Felizmente muitos deles já se encontram listados no website da iniciativa.

Outra boa melhoria (deveria chamar-lhe uma correcção) efectuada foi ao nível da usabilidade no website do Informix. Se aceder a http://ibm.com/software/data/informix, ou simplesmente http://ibm.com/informix ou até http://www.informix.com, irá ser redireccionado para uma página com uma ligação para "downloads". A partir daí pode navegar facilmente numa lista de downloads disponíveis.

Onde pode obter mais informação sobre este tema?:
Estas mudanças passa a ser efectivas na versão 11.50.xC7 fixpack.


NOTA [ 22 Julho de 2010]: Este artigo está desactualizado! As edições Ultimate-C para Windows e Mac foram retiradas. A versão Innovator-C ficará disponível para todas as plataformas e surge uma nova edição (Choice), com custos de licenciamento menores que a Growth Edition e com limites que se situam entre a Innovator-C e a Growth Edition.
Artigo com as últimas alterações:

http://informix-technology.blogspot.com/2010/07/informix-editions-revisited-versoes.html


Cumprimentos

Sunday, August 19, 2012

Panther: oninit -i ... ups... too late... or not / Panther: oninit -i ... ups... tarde de mais... ou não

This article is written in English and Portuguese
Este artigo está escrito em Inglês e Português

English version:

I hope that this one will be quick... How many of us have tried to initialize (oninit -i) an already initialized instance by mistake? Personally I don't think I did it, but our mind tends to erase bad experiences :) But we have heard too many stories like this. A problem in the environment setup and this can easily happen.
Well, the good folks from R&D tried to keep us safe from ourselves by introducing a new parameter called FULL_DISK_INIT. It's something that magically appears in the $ONCONFIG file with the value of 0, or that simply is not there... It's absence, or the value 0, means that if you run oninit -i and there is already an informix page in the rootdbs chunk, it will fail. Let's see an example:


panther@pacman.onlinedomus.net:fnunes-> onstat -V
IBM Informix Dynamic Server Version 11.70.UC1 Software Serial Number AAA#B000000
panther@pacman.onlinedomus.net:fnunes-> onstat -
shared memory not initialized for INFORMIXSERVER 'panther'
panther@pacman.onlinedomus.net:fnunes-> onstat -c | grep FULL_DISK_INIT
FULL_DISK_INIT 0
panther@pacman.onlinedomus.net:fnunes-> oninit -i

This action will initialize IBM Informix Dynamic Server;
any existing IBM Informix Dynamic Server databases will NOT be accessible -
Do you wish to continue (y/n)? y

WARNING: server initialization failed, or possibly timed out (if -w was used).
Check the message log, online.log, for errors.
panther@pacman.onlinedomus.net:fnunes-> onstat -m
shared memory not initialized for INFORMIXSERVER 'panther'

Message Log File: /usr/informix/logs/panther.log
Wed Oct 20 00:02:10 2010

00:02:10 Warning: ONCONFIG dump directory (DUMPDIR) '/usr/informix/dumps' has insecure permissions
00:02:10 Event alarms enabled. ALARMPROG = '/home/informix/etc/alarm.sh'
00:02:13 Booting Language from module <>
00:02:13 Loading Module
00:02:13 Booting Language from module <>
00:02:13 Loading Module
00:02:19 DR: DRAUTO is 0 (Off)
00:02:19 DR: ENCRYPT_HDR is 0 (HDR encryption Disabled)
00:02:19 Event notification facility epoll enabled.
00:02:19 IBM Informix Dynamic Server Version 11.70.UC1 Software Serial Number AAA#B000000
00:02:20 DISK INITIALIZATION ABORTED: potential instance overwrite detected.
To disable this check, set FULL_DISK_INIT to 1 in your config file and retry.

00:02:20 oninit: Fatal error in shared memory initialization

00:02:20 IBM Informix Dynamic Server Stopped.

00:02:20 mt_shm_remove: WARNING: may not have removed all/correct segments

Very nice. It didn't allow me to shoot myself in the foot.
And if we don't have it in the $ONCONFIG?:


panther@pacman.onlinedomus.net:fnunes-> vi $INFORMIXDIR/etc/$ONCONFIG
panther@pacman.onlinedomus.net:fnunes-> onstat -
shared memory not initialized for INFORMIXSERVER 'panther'
panther@pacman.onlinedomus.net:fnunes-> onstat -c | grep FULL_DISK_INIT
#FULL_DISK_INIT 0
panther@pacman.onlinedomus.net:fnunes-> oninit -i

This action will initialize IBM Informix Dynamic Server;
any existing IBM Informix Dynamic Server databases will NOT be accessible -
Do you wish to continue (y/n)? y

WARNING: server initialization failed, or possibly timed out (if -w was used).
Check the message log, online.log, for errors.
panther@pacman.onlinedomus.net:fnunes-> onstat -m
shared memory not initialized for INFORMIXSERVER 'panther'

Message Log File: /usr/informix/logs/panther.log
The default memory page size will be used.
00:06:43 Segment locked: addr=0x44000000, size=224858112

Wed Oct 20 00:06:44 2010

00:06:44 Warning: ONCONFIG dump directory (DUMPDIR) '/usr/informix/dumps' has insecure permissions
00:06:44 Event alarms enabled. ALARMPROG = '/home/informix/etc/alarm.sh'
00:06:44 Booting Language from module <>
00:06:44 Loading Module
00:06:44 Booting Language from module <>
00:06:44 Loading Module
00:06:50 DR: DRAUTO is 0 (Off)
00:06:50 DR: ENCRYPT_HDR is 0 (HDR encryption Disabled)
00:06:50 Event notification facility epoll enabled.
00:06:50 IBM Informix Dynamic Server Version 11.70.UC1 Software Serial Number AAA#B000000
00:06:52 DISK INITIALIZATION ABORTED: potential instance overwrite detected.
To disable this check, set FULL_DISK_INIT to 1 in your config file and retry.

00:06:52 oninit: Fatal error in shared memory initialization

panther@pacman.onlinedomus.net:fnunes->

The same. So if I'm trying to configure a second instance and I point the ROOTPATH to an existing one I'm safe.... But this raises one question: How can I really re-initialize an instance? I know what I'm doing, so let me work!... It's simple... If you really know what you're doing, set it to 1:


panther@pacman.onlinedomus.net:fnunes-> vi $INFORMIXDIR/etc/$ONCONFIG
panther@pacman.onlinedomus.net:fnunes-> onstat -c | grep FULL_DISK_INIT
FULL_DISK_INIT 1
panther@pacman.onlinedomus.net:fnunes-> oninit -i

This action will initialize IBM Informix Dynamic Server;
any existing IBM Informix Dynamic Server databases will NOT be accessible -
Do you wish to continue (y/n)? y
panther@pacman.onlinedomus.net:fnunes-> onstat -

IBM Informix Dynamic Server Version 11.70.UC1 -- On-Line -- Up 00:00:32 -- 369588 Kbytes

panther@pacman.onlinedomus.net:fnunes-> onstat -c | grep FULL_DISK_INIT
FULL_DISK_INIT 0
panther@pacman.onlinedomus.net:fnunes->

Perfect! It allowed me to initialize it, and immediately changed the FULL_DISK_INIT parameter to 0 to keep me safe again.
This has been in the feature request list for years. Now that it's implemented we should be jumping up and down in plain happiness... But I'm not. Why? Because instead of sending the deserved compliments to R&D for implementing this I want more!
This is terribly useful, and will save a lot of people from destroying their instances. But unfortunately I've seen many other cases of destruction that can't be avoided by this. A few examples:
  1. A chunk allocation for a second instance on the same machine (using RAW devices) overwrites another already used chunk from another instance
  2. A restore of an instance overwrites another (either fully or partially)
  3. A restore of an instance on the same machine using the rename chunks functionality uses an outdated rename chunks file (-rename -f FILE ontape option). This file doesn't have a few chunks that were recently added. So these chunks will be restored over the existing chunks!
So, what would make me jump would be something that covered all these scenarios. It would not be a simple ONCONFIG parameter and a change in oninit. It would require changes in more utilities and server components (onspaces, SQL Admin API, ontape, onbar...), but that would really keep us safe from our mistakes. For now this is a good sign, and if these questions worry you, be alert and if you have the chance make IBM know that it is important to you.

One instance was destroyed to bring this article to you... I'll spend another 30s to get the data back into it :)



Versão Portuguesa:

Espero que este seja rápido... Quantos de nós já tentámos inicializar (oninit -i/iy) uma instância já inicializada por engano? Pessoalmente não me recordo de me ter acontecido, mas a nossa mente tende a apagar episódios traumáticos :) Mas já ouvimos demasiadas estórias como esta. Basta um problema na configuração de um ambiente e isto pode acontecer facilmente.
Bem, os bons rapazes do desenvolvimento tentaram manter-nos a salvo de nós mesmos, através da introdução de um novo parâmetro chamado FULL_DISK_INIT. É algo que aparece magicamente no nosso $ONCONFIG com o valor 0, ou que simplesmente não está lá... A sua ausência ou o valor 0 significam que se tentarmos correr o oninit -i e já existir uma página Informix no nosso chunk do rootdbs irá falhar. Vejamos um exemplo:


panther@pacman.onlinedomus.net:fnunes-> onstat -V
IBM Informix Dynamic Server Version 11.70.UC1 Software Serial Number AAA#B000000
panther@pacman.onlinedomus.net:fnunes-> onstat -
shared memory not initialized for INFORMIXSERVER 'panther'
panther@pacman.onlinedomus.net:fnunes-> onstat -c | grep FULL_DISK_INIT
FULL_DISK_INIT 0
panther@pacman.onlinedomus.net:fnunes-> oninit -i

This action will initialize IBM Informix Dynamic Server;
any existing IBM Informix Dynamic Server databases will NOT be accessible -
Do you wish to continue (y/n)? y

WARNING: server initialization failed, or possibly timed out (if -w was used).
Check the message log, online.log, for errors.
panther@pacman.onlinedomus.net:fnunes-> onstat -m
shared memory not initialized for INFORMIXSERVER 'panther'

Message Log File: /usr/informix/logs/panther.log
Wed Oct 20 00:02:10 2010

00:02:10 Warning: ONCONFIG dump directory (DUMPDIR) '/usr/informix/dumps' has insecure permissions
00:02:10 Event alarms enabled. ALARMPROG = '/home/informix/etc/alarm.sh'
00:02:13 Booting Language from module <>
00:02:13 Loading Module
00:02:13 Booting Language from module <>
00:02:13 Loading Module
00:02:19 DR: DRAUTO is 0 (Off)
00:02:19 DR: ENCRYPT_HDR is 0 (HDR encryption Disabled)
00:02:19 Event notification facility epoll enabled.
00:02:19 IBM Informix Dynamic Server Version 11.70.UC1 Software Serial Number AAA#B000000
00:02:20 DISK INITIALIZATION ABORTED: potential instance overwrite detected.
To disable this check, set FULL_DISK_INIT to 1 in your config file and retry.

00:02:20 oninit: Fatal error in shared memory initialization

00:02:20 IBM Informix Dynamic Server Stopped.

00:02:20 mt_shm_remove: WARNING: may not have removed all/correct segments


Muito bem. Não me deixou dar um tiro no pé.
E se não tivermos o parâmetro no $ONCONFIG?:

panther@pacman.onlinedomus.net:fnunes-> vi $INFORMIXDIR/etc/$ONCONFIG
panther@pacman.onlinedomus.net:fnunes-> onstat -
shared memory not initialized for INFORMIXSERVER 'panther'
panther@pacman.onlinedomus.net:fnunes-> onstat -c | grep FULL_DISK_INIT
#FULL_DISK_INIT 0
panther@pacman.onlinedomus.net:fnunes-> oninit -i

This action will initialize IBM Informix Dynamic Server;
any existing IBM Informix Dynamic Server databases will NOT be accessible -
Do you wish to continue (y/n)? y

WARNING: server initialization failed, or possibly timed out (if -w was used).
Check the message log, online.log, for errors.
panther@pacman.onlinedomus.net:fnunes-> onstat -m
shared memory not initialized for INFORMIXSERVER 'panther'

Message Log File: /usr/informix/logs/panther.log
The default memory page size will be used.
00:06:43 Segment locked: addr=0x44000000, size=224858112

Wed Oct 20 00:06:44 2010

00:06:44 Warning: ONCONFIG dump directory (DUMPDIR) '/usr/informix/dumps' has insecure permissions
00:06:44 Event alarms enabled. ALARMPROG = '/home/informix/etc/alarm.sh'
00:06:44 Booting Language from module <>
00:06:44 Loading Module
00:06:44 Booting Language from module <>
00:06:44 Loading Module
00:06:50 DR: DRAUTO is 0 (Off)
00:06:50 DR: ENCRYPT_HDR is 0 (HDR encryption Disabled)
00:06:50 Event notification facility epoll enabled.
00:06:50 IBM Informix Dynamic Server Version 11.70.UC1 Software Serial Number AAA#B000000
00:06:52 DISK INITIALIZATION ABORTED: potential instance overwrite detected.
To disable this check, set FULL_DISK_INIT to 1 in your config file and retry.

00:06:52 oninit: Fatal error in shared memory initialization

panther@pacman.onlinedomus.net:fnunes->

Acontece o mesmo. Portanto de estiver a tentar configurar uma nova instância e por lapso apontar o ROOTPATH para outra já existente estou salvo... Mas isto levanta uma questao: Como posso re-inicializar uma instância? Eu sei o que estou a fazer, por isso deixem-me trabalhar!... É simples... Se sabe realmente o que está a fazer só tem de o definir para 1:


panther@pacman.onlinedomus.net:fnunes-> vi $INFORMIXDIR/etc/$ONCONFIG
panther@pacman.onlinedomus.net:fnunes-> onstat -c | grep FULL_DISK_INIT
FULL_DISK_INIT 1
panther@pacman.onlinedomus.net:fnunes-> oninit -i

This action will initialize IBM Informix Dynamic Server;
any existing IBM Informix Dynamic Server databases will NOT be accessible -
Do you wish to continue (y/n)? y
panther@pacman.onlinedomus.net:fnunes-> onstat -

IBM Informix Dynamic Server Version 11.70.UC1 -- On-Line -- Up 00:00:32 -- 369588 Kbytes

panther@pacman.onlinedomus.net:fnunes-> onstat -c | grep FULL_DISK_INIT
FULL_DISK_INIT 0
panther@pacman.onlinedomus.net:fnunes->

Perfeito. Deixou-me inicializar e imediatamente mudou o parâmetro FULL_DISK_INIT para 0 para me salvaguardar de novo.

Isto estava na lista de pedidos de coisas a implementar há anos. Agora que está implementado devíamos estar aos saltos de contentamento... Mas eu não estou. Porquê? Porque em vez de enviar os merecidos cumprimentos ao desenvolvimento quero mais!
Isto é tremendamente útil, e vai salvar muita gente de destruir as suas instâncias. Mas infelizmente eu tenho visto muitos outros casos de destruição que não podem ser evitados por isto. Alguns exemplos:
  1. Uma criação de um chunk para uma segunda instância na mesma máquina (usando RAW devices) sobrepõe outro chunk já em uso noutra instância
  2. Uma reposição de um backup sobrepõe outra instância (completa ou parcialmente)
  3. Uma reposição de um backup de uma instância, na mesma máquina, usando a funcionalidade de troca de paths dos chunks usa um ficheiro de rename desactualizado (opção -rename -f FICHEIRO do ontape). Este ficheiro não contém alguns chunks que foram adicionados recentemente. Portanto estes chunks serão restaurados sobre os existentes!
Assim, o que me deixaria aos pulos de contentamento seria algo que cobrisse todos estes cenários. Não seria tão simples quanto uma mudança no ONCONFIG e uma mudança no oninit. Requeriria mudanças em mais utilitários e componentes do servidor (onspaces, SQL Admin API, ontape, onbar....), mas isto sim, conseguiria manter-nos a salvo dos nossos erros. Por agora, esta funcionalidade é um bom sinal, e se estas questões o preocupam, esteja alerta e se tiver oportunidade faça com que a IBM saiba que isto é importante para si.

Uma instância foi destruída para fazer chegar este artigo até a si. Agora vou passar mais 30s a repôr-lhe os dados :)