Ir al contenido

Apuntes Prácticos

![](Pasted image 20250705204145.png) Se hace revocación en cascada por defecto. U4U4 y U5U5 mantienen sus permisos porque todavía hay un camino hasta el administrador. ![](Pasted image 20250705204207.png) Ahora U4U4 y U5U5 pierden sus permisos. ![](Pasted image 20250705204356.png) Esto generaría una excepción porque RESTRICT es una opción que impide revocar un privilegio si ese usuario ha dado ese privilegio a otros usuarios. ![](Pasted image 20250705204927.png) Si le quitamos la opción de dar privilegios y borramos al usuario U6U6 los pierde consecuentemente (los pierde por que se borra, no porquitar el grant option). ![](Pasted image 20250705205059.png)

Aquí el permiso lo concede el rol no el usuario, por lo que si eliminamos al usuario U1U1, U6U6 sigue manteniendo sus permisos. ![](Pasted image 20250705205228.png)

  • Atomicidad
  • Consistencia
  • Aislamiento
  • Durabiliadad
  • Activa
  • Parcialmente comprometida: ha ejecutado su última operación
  • Comprometida: cambios guardados en almacenamiento estable
  • Fallida
  • Abortada: retrocedidos los cambios tras pasar por fallida
  • Operaciones conflictivas (cada una es de una T diferente):

    • leer(A) y leer(A) no es conflictiva
    • leer(A) y escribir(A) es conflictiva
    • escribir(A) y leer(A) es conflictiva
    • escribir(A) y escribir(A) es conflictiva
  • Planificación secuencial: se ejecutan todas las operaciones de una misma transacción seguidas en bloque.

  • Planificación secuenciable: produce mismo resultado que la secuencial pero empleando concurrencia (no tiene por que ser secuenciable en cuanto a conflictos).

  • Planificación secuenciable en cuanto a conflictos: si se intercambian operaciones no conflictivas se obtiene la planificación secuencial.

![](Pasted image 20250704175118.png)

  • Grafo de precedencia: permite saber si la planificación es secuenciable en cuanto a conflictos (no tiene ciclos). TiTjT_i \rightarrow T_j, si tenemos 2 operaciones conflictivas y TiT_i ejecuta antes la suya que TjT_j En la tabla de arriba tendríamos T2T1T_2 \rightarrow T_1 y T2T3T_2 \rightarrow T_3
  • Planificación recuperable: aquella en la que todo par de transacciones T1T_1 y T2T_2 donde T2T_2 lee elementos escritos por T1T_1, la operación commit de T1T_1 aparece antes que la commit de T2T_2
T1T_1T2T_2
leer(A)
escribir(A)
leer(A)
leer(B)
commit
commit
  • Planificación sin cascada: aquella en la que todo par de transacciones T1T_1 y T2T_2 donde T2T_2 lee elementos escritos por T1T_1, la operación commit de T1T_1 aparece antes que la leer de T2T_2
T1T_1T2T_2
leer(A)
escribir(A)
commit
leer(A)
commit
  • Secuenciable
  • Lectura repetible: solo permite leer datos comprometidos, e impide que entre 2 lecturas de un dato en la transacción otra actualice ese dato
  • Lectura no repetible: solo permite leer datos comprometidos, pero permite que entre 2 lecturas de un dato en la transacción, otra actualice ese dato
  • No comprometida: permite leer datos no comprometidos

Tiene dos fases:

  • Fase de crecimiento: la transacción sólo obtiene bloqueos
  • Fase decrecimiento: la transacción sólo libera bloqueos
  • Punto bloqueo: punto de la transacción donde se produce la primera liberación

Sólo se pueden liberar los bloqueo-x una vez se ha comprometido la transacción.

Sólo se pueden liberar los bloqueos en general una vez se ha comprometido la transacción.

Emplea 2 operaciones para la conversión de bloqueos

  • subir de compartido a exclusivo
  • bajar de exclusivo a compartido Los desbloqueos se hacen una vez se compromete o aborta la transacción

![](Pasted image 20250704175118.png) Si suponemos que después de la última operación de cada TT hay un commit cumple tanto el protocolo estricto como el riguroso. Si no, no los cumple.

Expropiar y retroceder, cuando AA solicite un bloqueo que posee actualmente BB:

  • Esperar-Morir:
    • Si marca(A)<marca(B), AA espera
    • Si marca(A)>marca(B), AA retrocede
  • Herir-Esperar:
    • Si marca(A)<marca(B), BB retrocede
    • Si marca(A)>marca(B), AA espera
  • Grafo de Espera: se añadirá una arista TiTjT_i \rightarrow T_j cuando la transacción TiT_i solicite un elemento de datos que posea en ese momento la transacción TjT_j. Se borra cuando TjT_j deja de poseer un elemento que necesita TiT_i . Si hay ciclo hay interbloqueo.
T1T2T3
Bloquear-C (A)
Leer(A)
Bloquear-C (B)
Leer(B)
Bloquear-X (B)
Bloquear-C (A)
Leer(A)
Bloquear-X (A)
Desbloquear(B)
Escribir(B)
Desbloquear(A)
Desbloquear(B)
  • T1T2T_1 \rightarrow T_2
  • T2T3T_2 \rightarrow T_3
  • T2T1T_2 \rightarrow T_1 Hay un ciclo

Orden de secuencialidad/serialización: determina el orden de las transacciones en función sus marcas temporales usando el valor de validación como marca temporal. Para cumplir la prueba de validación se debe verificar una condición u otra:

  • fin(Ti)<inicio(Tj)fin(T_i) \lt inicio(T_j)
  • inicio(Tj)<fin(Ti)<validacion(Tj)inicio(T_j) \lt fin(T_i) \lt validacion(T_j) y además escritos(Ti)leidos(Tj)=escritos(T_i) \cap leidos(T_j) = \emptyset

T1T1 (lee (A,B), escribe: C), T2T2 (lee C, escribe A) y T3T3 (lee B, escribe D). ![](Pasted image 20250704192358.png) Orden de serialización: T1T2T3T_1 \rightarrow T_2 \rightarrow T_3

  • Prueba de validación para T2T_2:

    • fin(T1)<inicio(T2)fin(T_1) \lt inicio(T_2), 50<2050 \lt 20 falso
    • inicio(T2)<fin(T1)<validacion(T2)inicio(T_2) \lt fin(T_1) \lt validacion(T_2), 20<50<6020 \lt 50 \lt 60 verdadero
    • escritos(T1)leidos(T2)=escritos(T_1) \cap leidos(T_2) = \emptyset, CC=C \cap C = \emptyset falso, no pasa la prueba
  • Prueba de validación para T3T_3:

    • fin(T1)<inicio(T3)fin(T_1) \lt inicio(T_3), 50<3050 \lt 30 falso
    • inicio(T3)<fin(T1)<validacion(T3)inicio(T_3) \lt fin(T_1) \lt validacion(T_3), 30<50<6530 \lt 50 \lt 65 verdadero
    • escritos(T1)leidos(T3)=escritos(T_1) \cap leidos(T_3) = \emptyset, CB=C \cap B = \emptyset verdadero, pasa la prueba
  • Primer compromiso gana: cuando una TT está parcialmente comprometida se comprueba si hubo alguna transacción concurrente con TT que haya hecho alguna actualización sobre los elementos escritos por TT

    • Si no se encuentra dicha transacción: TT se compromete
    • Si se encuentra: TT se aborta
  • Primera actualización gana: cuando una TT intenta actualizar un elemento de datos, solicita una bloqueo de escritura sobre él. Se comprueba si alguna transacción concurrente con TT tiene un bloqueo sobre el mismo elemento:

    • Si no la hay:
      • Si ha sido actualizado por otra: TT aborta
      • Si no ha sido actualizado: TT puede continuar
    • Si la hay, TT espera a que acabe:
      • Si la otra aborta: TT puede continuar
      • Si la otra se compromete: TT aborta

Estos métodos no aseguran la secuencialidad pero no importa, funciona igual, el grafo de precedencia puede tener ciclos.

  • Bloque físico (en disco)

  • Bloque de memoria intermedia (en memoria intermedia)

  • Memoria intermedia (área de la RAM)

  • Área de Trabajo de TT (también en RAM y contiene copias de elementos de datos XX)

  • Entrada(B): transfiere BB de disco a memoria intermedia

  • Salida(B): transfiere BB de memoria intermedia a disco

  • leer(X): asigna el valor del elemento XX a la variable XiX_i del área de trabajo. Si el bloque BxB_x donde está XX no está en memoria intermedia se ejecuta Entrada(Bx)

  • escribir(X): asigna el valor de la variable XiX_i al elemento XX. Si el bloque BxB_x donde está XX no está en memoria intermedia se ejecuta Entrada(Bx)

  • Salida(B) se ejecuta cuando necesitamos espacio para meter otro bloque y lo vamos a poner en uno que ha sido escrito en memoria intermedia.

<Ti, E, Vant, Vpost> <Ti iniciada> , <Ti comprometida> , <Ti abortada>.

  • Modificación Inmediata: la TT modifica la bd mientras está activa
  • Modificación Diferida: la TT no modifica la bd hasta que está comprometida
  • deshacer(T): restaura el valor de todos los elementos actualizados por la transacción 𝑇 a sus valores anteriores.
  • rehacer(T): establece el valor de todos los elementos actualizados por la transacción 𝑇 a los valores nuevos.
  • Fase rehacer: partimos del último checkpoint, creamos la lista-deshacer. Cuando se encuentra un registro de la forma <Ti, Xj, V1, V2> o uno de solo-rehacer de la forma <Ti, Xj, V1> se aplica rehacer. Si se encuentra un registro de la forma <Ti iniciada> se añade a la lista-deshacer. Si se encuentra de la forma <Ti abortada> o <Ti comprometida> se elimina Ti de la lista-deshacer.
  • Fase deshacer: recorremos desde abajo hasta el checkpoint. Cuando veamos un registro de una transacción de la lista-deshacer escribimos un registro de compensación de la forma <Ti,Xj,V1> (SIEMPRE QUE NO USEMOS MODIFICACIÓN DIFERIDA). Al encontrar un registro de la forma <Ti iniciada> escribimos <Ti abortada> y se elimina de la lista-deshacer. Repetimos esto hasta que la lista-deshacer está vacía.

Fallo en el tiempo 12. A=20A = 20 y B=60B= 60 ![](Pasted image 20250704203334.png)

Con modificación inmediata: 1º Se rehace todo de arriba a abajo. Añadimos a T1T_1 a la lista-deshacer, después la sacamos y añadimos a T2T_2 2º Aplicamos deshacer a T2T_2 de abajo hacia arriba, escribimos un registro de solo rehacer y escribimos transacción abortada

ValorAValor AValorBValorBRegistroRegistroTiempoTiempo
2060<T1 iniciada>1
20602
2010<T1,B,60,10>3
20104
20105
2010<T1,B,60,10>6
20107
2010<T1 comprometida>8
2010<T2 iniciada>9
201010
1010<T2, A, 20, 10>11
2010<T2,A,20>12
2010<T2 abortada>13

Con modificación diferida: 1º Se rehace todo de arriba a abajo. Añadimos a T1T_1 a la lista-deshacer, después la sacamos y añadimos a T2T_2 2º Aplicamos deshacer a T2T_2 de abajo hacia arriba, escribimos un registro de solo rehacer y escribimos transacción abortada

ValorAValor AValorBValorBRegistroRegistroTiempoTiempo
2060<T1 iniciada>1
20602
2060<T1,B,10>3
20604
20605
2060<T1,B,10>6
20607
2010<T1 comprometida>8
2010<T2 iniciada>9
201010
2010<T2, A, 10>11
2010<T2 abortada>12

Cajón (bucket): unidad de almacenamiento de tamaño fijo que puede guardar uno o más registros. Para indexar en estos cajones los registros usamos funciones hash. ![](Pasted image 20250705193844.png) Si los cajones se llenan añadimos punteros a cajones de desbordamiento: ![](Pasted image 20250705193615.png) Podemos:

  • Buscar
  • Insertar
  • Borrar, en principio los cajones aunque sean de desbordamiento se quedan vacíos, no desaparecen.

Lo mismo que antes pero en vez de guardar en los cajones registros guardamos índices que apuntan a registros. ![](Pasted image 20250705194123.png)

![](Pasted image 20250705194519.png) Partimos de esto, donde el 00 de la izquierda es la profundidad global y el 00 de la derecha es la profundidad local. Si llenamos el cajón y se produce un desbordamiento hay que tener en cuenta lo siguiente:

  • Si la profundidad local es menor que la profundidad global no pasa nada, simplemente se crea un nuevo cajón y se enlaza con la tabla de la izquierda sin mayor complicación. Además aumentamos la profundidad local de cada cajón.

  • Si la profundidad local es igual que la profundidad global, habrá que aumentar tanto la profundidad global como la local en los cajones implicados, duplicando el tamaño de la tabla, creamos otro cajón y lo enlazamos. Ambas implican reordenar los elementos de los cajones y los punteros a los cajones. Sebastián para indexar usa los msb. ![](Pasted image 20250705194428.png)

  • Insertamos a mozart (00110011), y va al único bucket que hay.

  • Insertamos a Srinivasan(11111111), y va al al bucket que hay.

  • Sin embargo ahora insertamos a Wu (10101010), se desborda, comparamos profundidades y dividimos, redistribuimos nuevamente los elementos. Además incrementamos las profundidades ![](Pasted image 20250705194631.png)

  • Insertamos a Einstein(10011001), se vuelve a desbordar, como la profundidad local de ese cajón es menor, se crea uno nuevo se reordenan los punteros y se redistribuyen los elementos nuevamente. ![](Pasted image 20250705202715.png)

  • Hay ocasiones en las que debemos añadir un cajón de desbordamiento, cuando insertemos varios elementos que tengan la misma clave de inserción y superen el tamaño máximo del bucket. Por lo que simplemente se haría como al fondo de la imagen ![](Pasted image 20250705203047.png)

  1. Reordenar joins para reducir el tamaño de relaciones intermedias.
  2. Aplicar proyecciones tempranas para eliminar atributos innecesarios.

![](Pasted image 20250705210545.png)