Etiqueta

30 de julio de 2014

SQL en modo multitarea y multi-hilo (Parte 5 de 8)

Ejecución de un “worker”


El método $start() causa que la tarea especificada para el “worker” sea ejecutada como un subproceso en segundo plano. Por lo tanto no se produce pausa o espera alguna, la aplicación continua con su ejecución. Observe el siguiente ejemplo, el cual presupone que disponemos de la variable “iWorkerObj” correctamente definida, tal y como se puede observar a continuación…

;; iWorkerObj es una variable de tipo Object definida bajo instancia
Calculate Params as row(
iSQLText,'192.168.0.10’,iUser,iPassword,iDBName)
Do Params.$redefine(query,hostname,username,password,database)
Do iWorkerObj.$init(Params)
Do iWorkerObj.$start() Returns #F

…el método $run() (proporcionado sólo con fines de depuración y pruebas) es análogo a $start(), pero no debe ser usado en modo de explotación, ya que el “worker” es ejecutado sobre un único hilo quedando bloqueado hasta que la tarea asignada concluye.

Una vez iniciado el objeto “worker” puede ser ejecutado varias veces si así se desea, siempre y cuando el objeto-sesión suministrado siga estando disponible o bien el grupo de sesiones (sesión-pool) disponga de una o más sesiones libres de uso y las credenciales de inicio de sesión sigan siendo válidas. Cualquiera de las variables vinculadas (bind) ya suministradas, serán reutilizadas cada vez que se ejecute el “worker”.

Si se produce un error durante la ejecución de un $init(), $start() o $run(), se enviará un mensaje de error mediante las propiedades del objeto denominadas $códigoerror y $erroreext.

Procesado de los resultados de un “worker”


Una vez concluida la tarea asignada al “worker”, se invocará uno de los dos métodos de devolución disponibles:

  • $completed()
    Este método es invocado junto con un parámetro de tipo “row” que contiene dos columnas: “Results”: con una lista de una sola columna con cero o más conjuntos de resultados SQL y “Errors”: una lista de dos columnas con los valores ErrorCode y ErrorMsg.

  • $cancelled()
    Este método es invocado (sin paso de parámetros) y se produce cuando el usuario ejecuta un $cancel() sobre el objeto “worker” mientras está en ejecución. Los resultados pendientes son descartados.

A menudo sucede que una misma librería contiene objetos “worker” de diferentes tipos, cada uno de ellos con una tarea específica (sentencia SQL) e iniciados en modo asíncrono. Por lo tanto, la responsabilidad sobre el tratamiento de los resultados depende del uso que demos a los métodos indicados anteriormente, es en ellos donde se podrá obtener información sobre los resultados y ponerlos a disposición de la aplicación. A modo de ejemplo, describimos un posible uso del método $completed().

Calculate List as pRow.Results.1.1 ;;extrae el primer conjunto de resultados
Calculate Errors as pRow.Errors ;;extrae la lista con los posibles errores
If Errors.$linecount()>0
    Do method reportError(Errors)
Else
    Do method updateWindow(List) ;; procesa resultados
End If
Calculate iThreadCount as $cinst.$threadCount ;; obtiene el número de hilos en proceso


En caso de que los resultados devueltos por $completed() deban ser mostrados sobre una ventana, necesitaremos dibujar de nuevo su instancia (la de la ventana) y si se trata de un “remote-form”, el cliente deberá contactarse de nuevo con el servidor para su actualización.

Estados de un “worker”


Para consultar el estado en que se pueda encontrar un objeto “SQL worker” deberemos hacer uso de su propiedad $state. Que podrá informar de los siguientes:

  • kWorkerStateCancelled – El “worker” ha sido cancelado.
  • kWorkerStateClear – El “worker” se ha iniciado.
  • kWorkerStateComplete – El “worker” ha concluido.
  • kWorkerStateError – Se ha producido un error (ver $errortext).
  • kWorkerStateRunning – El “worker” está actualmente en ejecución.

Ejemplo de uso:

If iWorkerObj.$state=kWorkerStateRunning&iWorkerObj.$waitforcomplete=kTrue
     Calculate iMesg as 'En ejecución (esperando su conclusión)'
     Quit method
End If



21 de julio de 2014

SQL en modo multitarea y multi-hilo (Parte 4 de 8)

Iniciación de un objeto “worker”


El objeto “worker” deberá ser iniciado para un hilo, antes de ser ejecutado. Lo haremos mediante el suministro de una sentencia SQL y sus variables vinculadas (bind) que precise. Los datos necesarios para el inicio de una sesión con la base de datos o el nombre del grupo de sesiones (si estamos usando una pila de sesiones) también podrán ser suministrados durante el proceso de iniciación.

El parámetro de inicialización deberá ser suministrado con el método $init(), por medio de una variable de tipo “row”, que contendrá los valores para cada uno de sus atributos. El nombre de cada atributo corresponderá con el de cada una de sus columnas. A continuación, mostramos los que serán reconocidos por el objeto “worker”: (sensible al uso de mayúsculas y minúsculas)

Atributo Descripción
session Un objeto-sesión activo (session object) o referencia a un objeto-sesión. Deberá corresponder a una conexión en uso y utilizable.
poolname El nombre de un grupo de sesión existente. El “worker” tomará un objeto-sesión del grupo indicado y devolverá el control.
hostname Nombre host/IP del servidor de base de datos.
database Nombre de la base de datos a utilizar al inicio de sesión.
username Nombre del usuario a utilizar para el inicio de sesión.
password Contraseña del usuario para el inicio de sesión.
query Sentencia SQL que deberá ser ejecutada por el “worker”.
bindvars Es una lista con los valores de las variables vinculadas (bind). Las variables “bind” son leídas según el orden de las columnas. Si la lista contiene varias filas, la consulta será ejecutada para cada una de las filas.

Si se proporciona el atributo “session”, el resto de atributos de inicio de sesión, es decir, el “hostname”, “username” y “password” serán ignorados, ya que se presupone que el objeto-sesión está en estado utilizable. Nota importante: Si se usa de éste modo, la sesión deberá ser considerada como reservada para su uso exclusivo con “worker”. Cualquier intento de compartir un objeto-sesión que está siendo utilizado por un “worker”, que (dicho sea de paso) cuenta con su propio hilo de ejecución, los resultados serán impredecibles.

Al igual que en el caso del atributo “session”, los parámetros de inicio de sesión indicados también serán ignorados si se suministra el atributo “poolname”. En este modo, el “worker” intentará obtener una sesión del grupo de sesiones referenciado, liberándolo de nuevo tras su ejecución. En el caso de aportarse ambos atributos, (“sesión” y “poolname”) se ignorará el “poolname”.

Cuando no se aportan ninguno de ambos atributos, (“sesión” y “poolname”), se crea en ese instante un objeto-sesión interno. En éste caso deberán indicarse las credenciales para el inicio de la sesión, tales como el nombre de host/IP, nombre de usuario y su contraseña. Tenga en cuenta que, aunque estos atributos serán leídos al ejecutarse el método $init(), el “worker” no intentará iniciar la sesión hasta que los métodos $run() o $start() sean invocados. Éste modo de uso, causa que la sesión sea activada/desactivada automáticamente, cada vez que la tarea o “worker” se completa o bien es cancelada. En caso de que necesite modificar uno o más atributos de la sesión, antes de ejecutar el método $run() o $start(), podrá hacerlo mediante obtener una referencia al objeto-sesión al que pertenece el “worker”, usando para ello el método $sessionref(), por ejemplo, si quisiéramos modificar el puerto asignado, podríamos hacer lo siguiente:

Do iWorkerObj.$sessionref(lObjRef) Returns #F
Do lObjRef.$port.$assign(5435)


La texto SQL suministrada a través del atributo “query” podrá contener cualquier sentencia SQL, pero puesto que se trata de aprovechar la capacidad del multiproceso y multi-hilo, se espera que se trate de una declaración que normalmente le lleva una apreciable cantidad de tiempo al servidor para su ejecución, por ejemplo; una SELECT, UPDATE o DELETE con muchas filas y/o tablas implicadas. El texto de la “query” también podrá contener una o más variables vinculadas, especificadas en la forma ya conocida @[...].

Los valores de las variables vinculadas deberán suministrarse por medio del atributo “bindvars”. La lista es guardada por medio del método $init() y leida cuando se ejecuta la tarea o “worker”. En el caso de que la lista contenga varias filas, el “worker” volverá a ejecutar la sentencia SQL suministrada para cada una de las filas, pasando los valores de cada variable vinculada, en correspondencia con el orden de sus columnas.

Tenga en cuenta que el “worker” no tendrá en cuenta los nombres de las variables especificadas en el texto SQL, a la hora de establecer la correspondencia con sus valores, ya que ésta será establecida de acuerdo a su posición y no según sus nombres.

SQL en modo multitarea y multi-hilo (Parte 3 de 8)

Creación de objetos “SQL Worker”


Los objetos “worker” son creados como sub-clases (de tipo “SQL Worker”) de una clase objeto Omnis (Omnis object class). Por ejemplo, si queremos usarlo contra una base de datos Oracle, seleccionaríamos desde el cuadro de diálogo “Select Object”, el valor pertinente para su propiedad $superclase en: .ORACLE8DAM.Worker Objects\OracleWorker.
Naturalmente lo que queremos es poder acceder a las diferentes funciones del objeto “worker” desde el código de nuestra aplicación, para ello deberemos crear una o más variables de tipo objeto en el ámbito de instancia, fijando el objeto “worker” creado, como sub-tipo de dichas variables.