Você está na página 1de 48

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

PostgreSQL: heavyweight locks, lwlocks, deadlocks, spinlocks, pg_locks, row locks ... slvese quien pueda!
lvaro Herrera Command Prompt, Inc. alvherre@commandprompt.com

pgbr 2011 So Paulo, SP

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Introduccin
Esta charla es sobre locks su implementacin bloqueos en aplicaciones? WTF: locks sobre registros WTF: locks sobre transacciones

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Introduccin
Esta charla es sobre locks su implementacin bloqueos en aplicaciones? WTF: locks sobre registros WTF: locks sobre transacciones Esta charla NO es sobre MVCC Para eso, vaya a la de Bruce Momjian, que adems tiene traduccin simultnea
pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Introduccin
Esta charla es sobre locks su implementacin bloqueos en aplicaciones? WTF: locks sobre registros WTF: locks sobre transacciones Esta charla NO es sobre MVCC Clusters, replicacin, sharding, ...

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Locks en PostgreSQL

Tres tipos de locks en PostgreSQL: spinlocks LWLocks heavyweight locks

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Spinlocks

Mecanismo bsico: spinlocks objetos muy livianos rpida adquisicin (de no haber contencin) la CPU queda ocupada esperando hasta obtener el lock, si est ocupado
busy waiting en estricto rigor signica espera activa busy waiting normalmente es malo: la CPU queda ocupada

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Spinlocks en PostgreSQL

Implementacin en Postgres: macros TAS (test-and-set) y SPIN_DELAY (especie de pausa) TAS es un mecanismo atmico (incluso en multiprocesadores) cdigo especco en assembly para cada plataforma/compilador src/include/storage/s_lock.h src/backend/storage/s_lock.c src/backend/storage/spin.c

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Spinlocks en PostgreSQL (2)


Obtencin del lock: Si el spinlock est disponible: se setea un bit en memoria Si el lock est tomado por otro proceso: se itera el TAS hasta que se libere en cada iteracin: spin (girar) usando SPIN_DELAY de ah el nombre Liberar el lock: resetear el bit de memoria otro proceso que desee adquirir lo detectar en su siguiente iteracin

no hay deteccin de deadlocks!


pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Parntesis: Deadlocks

Recordatorio: es una especie de abrazo de oso forma ms simple:


proceso A adquiere lock X proceso B adquiere lock Y proceso A desea adquirir candado Y (se bloquea) proceso B desea adquirir candado X

todo el sistema est bloqueado sin esperanza

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Deadlocks

es fundamental evitar deadlocks o corregirlos corregir (detectar) un deadlock es costoso. Lo veremos ms adelante evitar deadlocks es responsabilidad del programador inventar reglas de manera que la situacin nunca se produzca

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Deadlocks y Spinlocks

en spinlocks, la regla es simple:

Jams obtener un spinlock cuando se tiene otro spinlock bloqueado


Para asegurar que esto se cumple, el uso de spinlocks es muy restringido Cada usuario de un spinlock normalmente slo ejecuta una o dos docenas de instrucciones con el spinlock bloqueado

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Usuarios de spinlocks

Se utilizan spinlocks para


proteger la implementacin de memoria compartida (ShmemLock) implementar LWLocks (struct LWLock en lwlock.c) proteger descriptor de cada buffer (de shared buffers) (BufferDesc en buf_internals.h) proteger informacin de control de checkpoints y XLog

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

LWLocks
LWLock: lightweight locks Mecanismo intermedio entre heavyweight locks y spinlocks ms capaces que spinlocks
dos modos de adquisicin: compartido (candado de slo lectura, ms de un proceso simultneamente) exclusivo (candado de escritura)

para proteger acceso a informacin de control almacenada en memoria compartida No hay deteccin de deadlocks

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

LWLocks (2)
Para adquirir un LWLock: adquirir su spinlock si el lwlock est libre: tomarlo si el lwlock est ocupado: ponerme a dormir (semforo SysV) liberar spinlock Al liberar un LWLock: adquirir el spinlock si hay alguien durmiendo en este lwlock (puede ser ms de uno), despertarlo liberar el spinlock

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

LWLocks (2)
Para adquirir un LWLock: adquirir su spinlock si el lwlock est libre: tomarlo si el lwlock est ocupado: ponerme a dormir (semforo SysV) liberar spinlock Al liberar un LWLock: adquirir el spinlock si hay alguien durmiendo en este lwlock (puede ser ms de uno), despertarlo liberar el spinlock

Ventaja sobre spinlock: el tiempo de espera no utiliza CPU


pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

LWLocks (3)

Es legal tomar ms de un lwlock simultneamente


... es obligatorio hacerlo en variadas ocasiones

Es responsabilidad del Postgreshacker asegurarse que no hay posibilidad de deadlock La regla: si se adquiere ms de uno, debe ser siempre en el mismo orden Tomar ms de dos es muy raro Todo esto requiere cuidadoso anlisis por parte del PGhacker

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

LWLocks (4)
Muchas operaciones regulares se protegen con LWLocks
escribir en WAL (WALInsertLock, WALWriteLock) generar un OID o un XID (OidGenLock, XidGenLock) examinar o modicar el contenido de ProcArray, la cola shared-inval, pg_clog, etc. examinar el contenido (datos) de un buffer (content_lock en BufferDesc)

En resumen: toda estructura ja (predenida) en memoria compartida Otra regla: un lwlocks slo debe mantenerse bloqueado por perodos muy cortos de tiempo
es decir: no realizar I/O con un lwlock bloqueado

excepcin: lwlocks usados para controlar I/O


lwlocks para I/O de un buffer (io_in_progress_lock en BufferDesc)
pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Heavyweight locks

Bloqueos sobre objetos de usuario (src/backend/storage/lmgr/lmgr.c) Estos son los realmente interesantes para la aplicacin
relacin (tabla, secuencia, vista, etc) extender (agrandar) una relacin pgina de una relacin tupla (registro, la) de una relacin transaccin transaccin virtual objeto (cualquier cosa que no sea una relacin) advisory

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Modos de adquisicin
AccessShare (SELECT) RowShare (SELECT FOR UPDATE, SELECT FOR SHARE) RowExclusive (UPDATE, INSERT, DELETE, etc) ShareUpdateExclusive (VACUUM, ANALYZE, CREATE INDEX
CONCURRENTLY)

Share (CREATE INDEX) ShareRowExclusive (no utilizado por el cdigo) Exclusive (no utilizado por el cdigo, excepto para bloquear ciertos catlogos en
ocasiones)

AccessExclusive (ALTER TABLE, DROP TABLE, TRUNCATE, REINDEX,


CLUSTER, VACUUM FULL)

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Tabla de conictos

AS AccessShare RowShare RowExclusive ShareUpdateExcl Share ShareRowExclusive Exclusive AccessExclusive

RS

RE

SUE

SRE

E X X X X X X X

X X

X X X X

X X X X X

X X X X X

X X X X X X

AE X X X X X X X X

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Deadlocks
Este tipo de locks es el nico que tiene deteccin de deadlocks (src/backend/storage/lmgr/deadlock.c) El sistema espera la obtencin del lock durante 1s Si despus de este tiempo no se ha obtenido el lock, el detector de deadlocks es ejecutado (deadlock.c) El detector de deadlocks recorre el grafo de waiterholder y determina si existe un ciclo en el grafo De existir un ciclo, signica que hay un deadlock El proceso que detecta primero el deadlock aborta su propia transaccin El grafo puede ser arbitrariamente complejo En trminos de aplicacin: todo cdigo que est posiblemente sujeto a deadlocks debera tener un bucle de reintento
pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Locks sobre transacciones

Cada transaccin tiene asociado un virtualxid desde el momento en que se inicia Cada transaccin obtiene un Xid al momento de hacer su primera escritura Cada transaccin adquiere ExclusiveLock en su Xid y vxid Se libera automticamente cuando termina Cuando una transaccin quiere esperar que otra termine, trata de obtener un ShareLock en ese Xid o vxid

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Examen de locks: vista pg_locks


pg_locks vista de sistema permite conocer los locks que se tienen o se esperan (slo hablamos de heavyweight locks aqu) muy til para comprender bloqueos entre procesos concurrentes ... algo difcil de leer :-( mltiples registros por proceso granted=f son candados que un proceso est esperando obtener granted=t son candados que un proceso tiene bloqueados

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

pg_locks ejemplo
alvherre=# select * from pg_locks where not granted; Record 1 locktype relation database 16384 relation 16398 page (null) (null) tuple virtualxid (null) transactionid (null) classid (null) objid (null) (null) objsubid virtualtransaction 3/2 pid 30786 mode AccessShareLock granted f f fastpath
pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

pg_locks ejemplo
alvherre=# select * from pg_locks where locktype = relation and database = 16384 and relation = 16398 and granted; Record 1 locktype relation database 16384 16398 relation page (null) tuple (null) virtualxid (null) (null) transactionid classid (null) objid (null) (null) objsubid virtualtransaction 2/3 pid 30778 mode AccessExclusiveLock granted t pgbr 2011 fastpath f

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

pg_locks ejemplo
Record 1 locktype relation database 16384 16398 relation page (null) tuple (null) virtualxid (null) transactionid (null) classid (null) objid (null) objsubid (null) virtualtransaction 2/3 pid 30778 AccessExclusiveLock mode granted t fastpath f
pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

campos usados cada tipo de lock

relation
database relation page tuple virtualxid transactionid classid objid objsubid

Lock a relation
pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

campos usados cada tipo de lock

extend
database relation page tuple virtualxid transactionid classid objid objsubid

Lock a relation for extension


pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

campos usados cada tipo de lock

page
database relation page tuple virtualxid transactionid classid objid objsubid

Lock a specic page within a relation


pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

campos usados cada tipo de lock

tuple
database relation page tuple virtualxid transactionid classid objid objsubid

Lock a specic tuple within a relation


pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

campos usados cada tipo de lock

virtualtransaction
database relation page tuple virtualxid transactionid classid objid objsubid

Lock a virtual Xid


pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

campos usados cada tipo de lock

transactionid
database relation page tuple virtualxid transactionid classid objid objsubid

Lock an Xid
pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

campos usados cada tipo de lock

object
database relation page tuple virtualxid transactionid classid objid objsubid

Lock a database object thats not a relation or part thereof


pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

campos usados cada tipo de lock

advisory
database relation page tuple virtualxid transactionid classid objid objsubid (1=int64 key; 2=2xint32 keys)

Lock an arbitrary user-specied key


(either a single int64 value, or two int32 values)
pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Una vista til sobre pg_locks


create view waiter_holder as select holder.*, waiter.virtualtransaction as waitervxid, waiter.pid as waiterpid, waiter.mode as waitermode from pg_locks holder join pg_locks waiter on holder.locktype = waiter.locktype and ( holder.database, holder.relation, holder.page, holder.tuple, holder.virtualxid, holder.transactionid, holder.classid, holder.objid, holder.objsubid ) is not distinct from ( waiter.database, waiter.relation, waiter.[... mismas columnas ...] ) and holder.granted and not waiter.granted;
pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Una vista til sobre pg_locks (2)


Record 1 relation 16384 16411 (null) ..... virtualtransaction 2/5 pid 30778 mode AccessExclusiveLock granted t f fastpath waitervxid 3/3 waiterpid 30786 waitermode AccessShareLock locktype database relation page
pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

qu est haciendo cada proceso?


SELECT holder_activity.procpid AS holder_pid, holder_activity.current_query AS holder_query, waiter_activity.procpid AS waiter_pid, waiter_activity.current_query AS waiter_query FROM pg_stat_activity AS holder_activity JOIN waiter_holder ON (holder_activity.procpid = pid) JOIN pg_stat_activity AS waiter_activity ON (waiter_activity.procpid = waiterpid);

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

qu est haciendo cada proceso? (2)

holder_pid holder_query waiter_pid waiter_query

Record 1 5655 <IDLE> in transaction 5665 drop table fk;

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Locks sobre registros


Row locks No aparecen en pg_locks excepto temporalmente Bloqueo de largo plazo utiliza un row mark row mark es una marca especial (en disco) en el registro mismo no hay representacin del row mark en memoria (ocupara mucha) Para examinar row marks existentes, contrib/pgrowlocks
debe recorrer la tabla completa para obtenerlos

Candado exclusivo: SELECT FOR UPDATE Candado compartido: SELECT FOR SHARE
pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Locks sobre registros: protocolo de obtencin

Protocolo de obtencin:
Bloquear el buffer Obtener heavyweight lock sobre registro Si est tomado el row mark,
desbloquear el buffer dormir en el lock del Xid de la transaccin que lo tiene obs: lock sobre registro queda tomado

Si no,
marcar el registro con mi Xid (row mark) liberar el heavyweight lock

desbloquear el buffer

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Llaves forneas

La implementacin de llaves forneas usa locks de registros Internamente se usa SELECT FOR SHARE sobre el registro referenciado (src/backend/utils/adt/ri_triggers.c Esto asegura que el registro no se borrar hasta despus de que la transaccin que crea la referencia haya terminado

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Llaves forneas

La implementacin de llaves forneas usa locks de registros Internamente se usa SELECT FOR SHARE sobre el registro referenciado (src/backend/utils/adt/ri_triggers.c Esto asegura que el registro no se borrar hasta despus de que la transaccin que crea la referencia haya terminado ... pero tambin impide hacer un UPDATE sobre el registro
... an cuando dicho UPDATE no afecte la permanencia de la llave

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Desarrollo en progreso

optimizacin de spinlocks en >32 CPUs 9.2: heavyweight locks usan fast path SELECT FOR KEY SHARE

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Conclusin

Los mecanismos de locking son complicados ...

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Conclusin

Los mecanismos de locking son complicados ... ... pero es preciso comprenderlos para depurar ciertos problemas en PostgreSQL

pgbr 2011

intro

spinlocks

lwlocks

heavyweight locks

pg_locks

locks en las

futuro

nal

Preguntas?

pgbr 2011

Você também pode gostar