You are on page 1of 5

Buffer y bloqueos en Visual FoxPro Resumen

Dnde comenzamos?
Parece que trabajar con datos en buffer en Visual FoxPro causa mucha confusin. Creo que es en gran medida debido a la
confusin en la implementacin del buffer y en parte tambin, por problemas de nomenclatura (por estndares
convencionales) asociados al tema.
Por ejemplo, para definir buffer para un archivo DBF de Visual FoxPro, que es una tabla, tenemos que utilizar la funcin
CURSORSETPROP(), que est excesivamente sobrecargada. Por qu no tener una funcin separada, sin ambigedades, "
SetBufferMode()"? Para confirmar una transaccin pendiente el comando es END TRANSACTION. Por qu no "COMMIT"
como en el resto de los lenguajes de bases de datos - una opcin que incluso es ms peculiar ya que el estndar
"ROLLBACK" se utiliza para revertir una transaccin?
Adems, quizs debido a que Visual FoxPro implementa el bloqueo de los registros (lo contrario a "Pgina"), el hecho de
controlar la colocacin y liberacin de los bloqueos est inseparablemente enlazada con el buffer. Por ejemplo, para permitir
buffer de filas, (que solamente opera sobre un slo registro) SET MULTILOCKS debe estar en "ON". De acuerdo con el archivo
Ayuda, esta configuracin solamente determina la capacidad de Visual FoxPro para bloquear mltiples registros en la misma
tabla - y que de todas formas, est limitado a la actual sesin de datos. Esto no parece ser muy lgico y no es realmente
sorprendente que la gente est totalmente confusa.

Qu significa "buffer"?
El principio es realmente muy simple. Cuando hace cambios en algn dato, esos cambios no es escriben en la tabla fuente,
en lugar van a un rea de almacenaje (el "Buffer") hasta el momento en que le indica a Visual FoxPro que deben ser
guardados en el almacn permanente o eliminarlos. Esta rea de almacenaje es lo que, en la actualidad, ve en Visual FoxPro
cuando se utiliza una tabla de buffer, en realidad un cursor actualizable basado en la tabla original. Todos los cambios se han
hecho sobre este cursor y slo se escriben en la tabla cuando se utiliza el comando "update" adecuado.

Estrategias de buffer
La estrategia de buffer determina cundo y cmo se almacenan en la tabla los cambios que se encuentran en el buffer.
Existen tres opciones:

No se emplea buffer: Esta va es solamente una opcin para las versiones anteriores a Visual Foxpro versin 3.0 y
es adems, el comportamiento predeterminado actualmente para las tablas de Visual FoxPro. Cualquier cambio
hecho en una tabla va directamente e inmediatamente a la tabla original. No hay posibilidad de "deshacer" sin que
se haya programado explcitamente - utilizando Scatter y Gather, por ejemplo. Se establece al asignar "1" como
parmetro a CursorSetProp()

Buffer de filas: Los cambios no se han enviado a la tabla original a menos que ocurran una de estas dos cosas. O
hay una llamada explcita a la funcin TableUpdate(), o el puntero del registro se mueve dentro de la tabla original.
Vea que CUALQUIER movimiento del puntero del registro, aunque sea iniciado por una tabla que est en buffer de
filas, siempre causa un TableUpdate() "implcito". Establezca 2 3 como parmetro para CursorSetProp().

Buffer de tabla: Los cambios nunca se envan automticamente a la tabla original, a menos que exista una llamada
a un comando TableUpdate() o TableRevert() siempre debe afectar los cambios que estn guardados en el buffer.
Intentar cerrar una tabla con buffer mientras tiene cambios no cometidos provoca que Visual FoxPro genere un error
en la versin 3.0; pero este comportamiento cambi en versiones anteriores por tanto, los cambios pendientes
simplemente se pierden. (No hay error; ni advertencia de que los cambios se van a perder). Se establece asignando
4 5 como parmetro para CursorSetProp().

Hasta este punto se est preguntando, por qu hay DOS parmetros posibles para cada una de las estrategias que
implementan buffer. La respuesta es, como se indica en la introduccin, debido a que hay dos estrategias de bloqueo.

Estrategias de bloqueo
Visual FoxPro necesita bloquear el registro fsico en la tabla mientras se realizan los cambios en su contenido y existen dos
vas con las que se puede establecer el bloqueo automtico (opuesto al uso explcito de las funciones RLock()/FLock())

Bloqueo pesimista: El registro se bloquea en cuanto un usuario comienza a hacer cambios (El bloqueo en realidad
ocurre en cuanto se oprime cualquier tecla vlida). Esto evita que cualquier otro usuario pueda hacer o guardar

cambios sobre este registro hasta tanto el usuario actual haya completado sus cambios y liberado el registro tanto
guardando o revirtiendo los cambios.

Bloqueo optimista: Un intento de bloqueo del registro se hace solamente cuando los cambios se comienzan a
enviar a la tabla. Esto significa que incluso mientras un usuario hace cambios en el dato, el registro permanece
disponible a otros usuarios, los que tambin podran, y posiblemente guardarn, cambios en el mismo registro
mientras el primer usuario estn aun trabajando en el.

Modos de buffer
El modo de buffer para una tabla es, por tanto, la combinacin especfica de las estrategias de Buffer y Bloqueo que se
aplican. Existe un total de 5 modos de buffer para una tabla como se ilustra en la Tabla 1.
Tabla 1. Modos de Buffer en Visual FoxPro
Mod
o

Bloqueo

Buffer

Pesimista

Ningun
o

Pesimista Fila

El bloqueo se establece por el evento KeyPress. El movimiento del puntero de registro obliga a
Guardar

Optimist
a

El bloqueo se establece por TableUpdate(). El movimiento del puntero de registro obliga a


Guardar

Pesimista Tabla

El bloqueo se establece por el evento KeyPress. Guardar se debe iniciar explcitamente

Optimist
a

El bloqueo se establece por el evento TableUpdate(). Guardar se debe iniciar explcitamente

Fila

Tabla

Comentarios
nica opcin para FP2.x, predeterminado para tablas VFP

Al trabajar con Visual FoxPro, debemos ser cuidadosos al distinguir entre estrategias individuales, que se especifican
directamente para Buffer y Bloqueo, y el modo buffer que resulta de la combinacin de ellos. Desafortunadamente, como
hemos visto, Visual FoxPro es de por s, menos cuidadoso con esta distincin.

Qu significa todo esto cuando creamos formularios enlazados a datos?


He aqu donde las cosas comienzan a ponerse un poco ms complejas (y no es solamente por la nomenclatura).
Consideremos una situacin normal donde las tablas se agregan al formulario por el entorno de datos nativo. El formulario
tiene una propiedad llamada "Buffermode" que tiene tres valores posibles:

0 Ninguno (predeterminado)

1 Pesimista

2 Optimista

Vea que esto se refiere en realidad a las opciones para la estrategia de bloqueo y no tiene nada que ver con el buffer para
nada !! El hecho por el cual el formulario determina la estrategia buffer es por sus tablas todas por si mismo, basadas en su
utilizacin. Si un formulario utiliza dos tablas que tienen una relacin de uno a muchos, muestran el lado "muchos" de la
relacin de diferentes formas.
Si la tabla "muchos" se utiliza como origen de datos para el control grid, para el formulario, se abre con buffer de tabla. Sin
embargo, si la tabla "muchos" se emplea para enlazar con controles que solamente muestran una fila de la tabla cada vez
entonces, el buffer para la tabla va a ser lo mismo que para "una" tabla para toda de configuracin de la propiedad
Buffermode del formulario.
Si crea un pequeo formulario de prueba y ejecuta todas sus opciones para la propiedad Buffermode de un formulario, puede
ver que incluso con la propiedad BufferMode establecida en 0-(Ninguna) el cursor creado por Visual FoxPro est aun abierto
en modo buffer de fila cuando las tablas se abren desde el entorno de datos del formulario. Es como si para el formulario "No
buffer" y "Bufer de filas" fuera lo mismo.

Sin embargo, este NO es el caso si las tablas se abren directamente con el comando USE. Si las tablas se abren
explcitamente en el mtodo Load(), entonces la propiedad Buffermode no tiene impacto en lo absoluto, y las tablas se abren
en dependencia de los parmetros apropiados en la Sesin de datos. Para formularios que corren en la sesin
predeterminada de datos (DataSession = 1) se utilizan los parmetros especificados en la ventana Opciones. Vea que en la
ventana Opciones, las opciones, en realidad establecen la configuracin del modo de bufer. Tiene las 5 opciones que se
corresponden con lo 5 modos definidos antes, en la Tabla 1, y los que utilizan los mismos identificadores que la funcin
CursorSetProp(). Si el formulario se ejecuta en sesin privada de datos, entonces, las tablas abiertas con el comando USE se
configuran en dependencia de la configuracin establecida para esa sesin de datos y, de forma predeterminada, no sern
alojadas en buffer.

Aun confundido?
Lo ms que puedo decir es que la situacin es realmente como sigue:

Para las tablas abiertas por el entorno de datos del formulario, no importa si el formulario tiene Datassesion con
valor Default o Private. Las tablas siempre tienen almacenamiento en buffer, al menos en modo Optimista de filas.

La propiedad BufferMode del formulario en realidad determina la estrategia de bloqueo, no el modo de buffer; pero
solo para tablas que han sido abiertas en el entorno de datos del formulario.

En la sesin de datos actual, las tablas que han sido abiertas explcitamente tienen ambas estrategias: buffer y
bloqueo establecidas en dependencia de la ventana Opciones.

En la sesin Privada de datos, las tablas que han sido abiertas explcitamente tienen sus estrategias de buffer y
bloqueo establecidas de acuerdo a los parmetros que se han aplicado para esta sesin (Predeterminado = "No
Buffering")

Estos resultados se pueden verificar estableciendo varias opciones en un formulario sencillo y mostrando el resultado
que se obtiene por CURSORGETPROP("BUFFERING")

Entonces, cmo debemos establecer el buffer para un formulario?


La respuesta corta , como siempre, es "depende". Si utiliza el entorno de datos del formulario para abrir las tablas entonces,
puede normalmente dejar la opcin al Visual FoxPro. En caso contrario puede simplemente emplear la funcin
CursorSetProp() en su cdigo para configurar cada tabla como sea necesario. De cualquier manera necesita ser consciente de
las consecuencias para que pueda programar sus actualizaciones rpidamente.

Utilizar BufferModeOverride
La clase dataenvironment posee una propiedad para cada tabla (o, mejor dicho, "cursor") llamado "BufferModeOverride".
Esta propiedad va a fijar el modo del buffer para esa tabla (y slo esa tabla) a una de las estas seis opciones - si, es
correcto, SEIS opciones, no cinco - veamos:

0 Ninguno

1 (Predeterminado) Utilizar la configuracin del formulario.

2 Bffer pesimista de fila

3 Buffer optimista de fila

4 Buffer pesimista de tabla

5 Buffer optimista de tabla

Existen dos puntos sobre los que hay que prestar atencin. Primero, Vea que mientras los nmeros del 2 al 5 se
corresponden con los parmetros de CursorSetProp() y son aquellos mismos que estn disponibles desde el dilogo
Opciones, el valor requerido para la configuracin "ninguno" ahora es 0 en lugar de 1. He aqu otra inconsistencia en la
configuracin del buffer. Segundo, vea que el valor predeterminado para esta propiedad es "1 - Utiliza la configuracin de
formularios". Cuando se refiere a configuracin de formularios, se refiere, por supuesto a la propiedad "BufferMode", la que

como ya hemos visto en realidad se encarga de definir la estrategia de bloqueo a aplicar. No existe configuracin del
formulario para controlar buffer !!.
Habiendo dicho esto, la configuracin de la propiedad BufferModeOverride va a asegurar que la tabla se abre utilizando el
modo buffer que usted ha especificado. Al menos esta propiedad ha sido nombrada correctamente, sobreescribe todo lo
dems y fuerza la tabla a un modo especial de buffer en todas las situaciones.

Utilizar CursorSetProp()
Independientemente de cmo fue abierta la tabla, siempre puede utilizar la funcin CursorSetProp() para cambiar el modo
buffer de una tabla. Sin embargo, si est utilizando el entorno de datos del formulario para abrir sus tablas, entonces, tiene
dos opciones en dependencia de si su formulario utiliza sesin privada de datos o sesin actual de datos. En el primer caso,
puede establecer simplemente el modo requerido en la ventana Opciones y olvidarse de ello. Todas las tablas se van a abrir
siempre con esa configuracin y siempre sabr en qu estado se encuentra. Si utiliza una sesin privada de datos entonces,
necesita hacer dos cosas. Primero, necesita asegurarse de que el entorno de datos est configurado para soportar buffer.
Algunos parmetros de entorno se limitan a la sesin de datos actual y puede que necesite cambiar el comportamiento
predeterminado o alguno, o todos los siguientes (vea el tema SET DATASESSION en el archivo ayuda para una lista completa
de parmetros afectados):

SET MULTILOCKS - Debe ser ON para permitir buffer, predeterminado OFF

SET DELETED - Predeterminado OFF

SET DATABASE - "No database" es el predeterminado en una sesin Privada

SET EXCLUSIVE - El predeterminado es OFF para una sesin Privada

SET LOCK - Predeterminado OFF

SET COLLATE - Predeterminado es "MACHINE"

SET EXACT - Predeterminado es OFF

Lo segundo que necesita es especificar explcitamente el modo buffer de cada tabla utilizada en la funcin CursorSetProp()
con el parmetro apropiado porque la configuracin en la ventana Opciones no se puede aplicar a la sesin privada de datos.

Entonces, qu modo de buffer debo utilizar en mis formulario?


Para nosotros la respuesta es sencilla. Siempre debe utilizar estrategia de buffer de tabla con bloqueo optimista (es decir
modo de buffer 5). La razn es simplemente que, con la excepcin de creacin de un ndice, no hay nada que pueda hacer en
otro modo que no pueda hacer en este modo. Mientras el buffer de filas puede ser utilizado en desarrollo, no creemos que
tienen cabida en una aplicacin en funcionamiento. La razn es simplemente que existe muchas formas en las que puede ser
desencadenada la funcin TableUpdate() implcito (causado por el movimiento del puntero de registro) y no todos los que
estn por debajo de nuestro control directo. Por ejemplo, la funcin KeyMatch() est definida en el archivo Ayuda, como;
Busca una clave de ndice en una etiqueta o un archivo de ndice.
Parece suficientemente inofensivo - seguramente buscar un archivo ndice no puede causar problemas. Pero una nota (en la
seccin Observaciones justo al final del tema) indica que:
KEYMATCH( ) devuelve el puntero de registro al registro donde estaba originalmente antes de ejecutar KEYMATCH( ).
Aqu se bloquea! Seguramente "devuelve el puntero de registro" implica que mueve el puntero del cursor - lo que en efecto
- hace. La consecuencia es que si est utilizando el buffer de filas y quiere verificar por clave duplicados utilizando
keymatch(), puede realizar inmediatamente cualquier cambio pendiente. (Por supuesto, en la versin 6 o despus pueden
siempre utilizar en su lugar IndexSeek(). Sin embargo, el mismo problema surge cuando muchos de los comandos y
funciones que operan sobre una tabla - especialmente el ms viejo introducido en FoxPro antes los das de buffer (e.g.
CALCULATE, SUM y AVERAGE).

Aun ms importante, el hecho de que configure una tabla para buffer de tabla no lo previene de que la tabla como si en
realidad hubiera buffer de filas. Ambas funciones TableUpdate() y TableRevert(). Esto puede significar que tiene que escribir
un poco ms de cdigo; pero puede evitar muchos problemas.

Cambiar el modo de buffer de la tabla


Hemos dicho, al inicio de la ltima sesin, que puede utilizar siempre CursorSetProp() para establecer o cambiar el modo de
buffer de una tabla. Esto es cierto; pero si la tabla ya ha tenido asignado un modo buffer, puede no ser tan sencillo porque al
cambiar el estado de buffer forzara a Visual FoxPro a verificar el estado de cualquier buffer existente.
Si la tabla tiene buffer de filas, y tiene cambios no confirmados, Visual FoxPro los enva y permite cambiar el modo. Si el
destino tiene buffer de tablas, y trata de cambiar su modo de buffer mientras existen cambios no confirmados, Visual FoxPro
se queja y manda el error 1545 ("El bfer de tablas para el alias "nombre" contiene cambios no confirmados"). Esto es un
problema porque no puede indexar una tabla, o hacerla libre una tabla o cursor transactable, los que mientras la tabla tiene
buffer, por tanto es la nica va de hacer estas cosas, temporalmente, a buffer de filas. Por supuesto, la solucin es siempre
suficiente - asegrese slo de que no hay cambios pendientes antes de que intente cambiar el modo de buffer.

You might also like