El módulo amcheck proporciona funciones que te permiten
verificar la consistencia lógica de la estructura de las relaciones.
Las funciones de comprobación de B-Tree verifican varios invariantes en la
estructura de la representación de relaciones particulares. La
corrección de las funciones del método de acceso detrás de los escaneos de índices y
otras operaciones importantes depende de que estos invariantes se cumplan siempre.
Por ejemplo, ciertas funciones verifican, entre otras cosas,
que todas las páginas B-Tree tengan elementos en orden “lógico” (por ejemplo,
para índices B-Tree en text, las tuplas del índice deben estar en
orden léxico intercalado). Si ese invariante particular de alguna manera no se cumple,
podemos esperar que las búsquedas binarias en la página afectada guíen
incorrectamente los escaneos de índices, lo que resulta en respuestas erróneas a las
consultas SQL. Si la estructura parece ser válida, no se produce ningún error.
Mientras se ejecutan estas funciones de comprobación, el search_path se cambia temporalmente a pg_catalog,
pg_temp.
La verificación se realiza utilizando los mismos procedimientos que los utilizados por los propios escaneos de índices, que pueden ser código de clase de operador definido por el usuario. Por ejemplo, la verificación del índice B-Tree se basa en las comparaciones realizadas con una o más rutinas de la función de soporte 1 de B-Tree. Consulta el Section 36.16.3 para obtener detalles sobre las funciones de soporte de la clase de operador.
A diferencia de las funciones de comprobación de B-Tree que informan de la corrupción
mediante la generación de errores, la función de comprobación de montón (heap)
verify_heapam comprueba una tabla e intenta devolver un conjunto
de filas, una fila por cada corrupción detectada. A pesar de esto, si las utilidades
de las que depende verify_heapam están corruptas, la función
puede no ser capaz de continuar y en su lugar puede generar un error.
El permiso para ejecutar funciones de amcheck se puede otorgar
a no superusuarios, pero antes de otorgar dichos permisos se debe prestar cuidadosa
atención a los problemas de seguridad y privacidad de los datos. Aunque los
informes de corrupción generados por estas funciones no se centran tanto en el contenido
de los datos corruptos sino en la estructura de esos datos y la naturaleza
de las corrupciones encontradas, un atacante que obtenga permiso para ejecutar estas
funciones, especialmente si el atacante también puede inducir la corrupción, podría
deducir algo de los propios datos a partir de tales mensajes.
bt_index_check(index regclass, heapallindexed boolean, checkunique boolean) returns void
bt_index_check comprueba que su objetivo, un
índice B-Tree, respete una variedad de invariantes. Ejemplo de uso:
test=# SELECT bt_index_check(index => c.oid, heapallindexed => i.indisunique),
c.relname,
c.relpages
FROM pg_index i
JOIN pg_opclass op ON i.indclass[0] = op.oid
JOIN pg_am am ON op.opcmethod = am.oid
JOIN pg_class c ON i.indexrelid = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE am.amname = 'btree' AND n.nspname = 'pg_catalog'
-- No comprobar tablas temporales, que pueden ser de otra sesión:
AND c.relpersistence != 't'
-- La función puede arrojar un error cuando se omite esto:
AND c.relkind = 'i' AND i.indisready AND i.indisvalid
ORDER BY c.relpages DESC LIMIT 10;
bt_index_check | relname | relpages
----------------+---------------------------------+----------
| pg_depend_reference_index | 43
| pg_depend_depender_index | 40
| pg_proc_proname_args_nsp_index | 31
| pg_description_o_c_o_index | 21
| pg_attribute_relid_attnam_index | 14
| pg_proc_oid_index | 10
| pg_attribute_relid_attnum_index | 9
| pg_amproc_fam_proc_index | 5
| pg_amop_opr_fam_index | 5
| pg_amop_fam_strat_index | 5
(10 rows)
Este ejemplo muestra una sesión que realiza la verificación de los
10 índices de catálogo más grandes en la base de datos “test”.
Se solicita la verificación de la presencia de tuplas de montón como tuplas de índice
para el subconjunto que son índices únicos. Dado que no se
genera ningún error, todos los índices probados parecen ser lógicamente
consistentes. Naturalmente, esta consulta podría cambiarse fácilmente para
llamar a bt_index_check para cada índice de la
base de datos donde se admita la verificación.
bt_index_check adquiere un bloqueo AccessShareLock
en el índice objetivo y en la relación de montón a la que pertenece. Este modo de bloqueo
es el mismo adquirido en las relaciones por sentencias SELECT simples.
bt_index_check no verifica invariantes
que abarquen relaciones hijo/padre, pero verificará la
presencia de todas las tuplas de montón como tuplas de índice dentro del índice
cuando heapallindexed sea
true. Cuando checkunique
sea true, bt_index_check
comprobará que no sea visible más de una de las entradas duplicadas en el
índice único. Cuando se requiere una comprobación rutinaria y ligera de
corrupción en un entorno de producción en vivo, el uso de
bt_index_check a menudo proporciona el mejor
equilibrio entre la rigurosidad de la verificación y la limitación del
impacto en el rendimiento y la disponibilidad de la aplicación.
bt_index_parent_check(index regclass, heapallindexed boolean, rootdescend boolean, checkunique boolean) returns void
bt_index_parent_check comprueba que su
objetivo, un índice B-Tree, respete una variedad de invariantes.
Opcionalmente, cuando el argumento heapallindexed
es true, la función verifica la
presencia de todas las tuplas de montón que deberían encontrarse dentro del
índice. Cuando checkunique
es true, bt_index_parent_check
comprobará que no sea visible más de una de las entradas duplicadas en el
índice único. Cuando el argumento opcional rootdescend
es true, la verificación vuelve a buscar
tuplas en el nivel de hoja realizando una nueva búsqueda desde la
página raíz para cada tupla. Las comprobaciones que puede realizar
bt_index_parent_check son un superconjunto de las
comprobaciones que puede realizar bt_index_check.
bt_index_parent_check puede considerarse como
una variante más rigurosa de bt_index_check:
a diferencia de bt_index_check,
bt_index_parent_check también comprueba
invariantes que abarcan relaciones padre/hijo, incluyendo la comprobación
de que no falten enlaces descendentes (downlinks) en la estructura del índice.
bt_index_parent_check sigue la convención general
de generar un error si encuentra una inconsistencia lógica u otro problema.
bt_index_parent_check requiere un bloqueo ShareLock
en el índice objetivo (también se adquiere un ShareLock
en la relación de montón). Estos bloqueos evitan la modificación concurrente de datos
por parte de comandos INSERT, UPDATE y DELETE.
Los bloqueos también evitan que la relación subyacente sea procesada concurrentemente por
VACUUM, así como por todos los demás comandos de utilidad. Ten en cuenta
que la función mantiene los bloqueos solo mientras se ejecuta, no durante toda la transacción.
La verificación adicional de bt_index_parent_check
tiene más probabilidades de detectar varios casos patológicos. Estos casos pueden involucrar
una clase de operador B-Tree implementada incorrectamente utilizada por el índice comprobado,
o, hipotéticamente, errores no descubiertos en el código del método de acceso al índice B-Tree subyacente.
Ten en cuenta que bt_index_parent_check no se puede utilizar cuando
el modo hot standby está habilitado (es decir, en réplicas físicas de solo lectura),
a diferencia de bt_index_check.
gin_index_check(index regclass) returns void
gin_index_check comprueba que su índice GIN objetivo
tenga relaciones consistentes de tuplas padre-hijo (ninguna tupla padre
requiere ajuste de tupla) y que el grafo de páginas respete los invariantes de
árbol equilibrado (las páginas internas hacen referencia solo a páginas hoja o solo a
páginas internas).
Tanto bt_index_check como
bt_index_parent_check emiten mensajes de registro
sobre el proceso de verificación a niveles de gravedad
DEBUG1 y DEBUG2. Estos mensajes proporcionan
información detallada sobre el proceso de verificación que puede ser de interés para los
desarrolladores de PostgreSQL. Los usuarios avanzados
también pueden encontrar útil esta información, ya que proporciona contexto adicional
en caso de que la verificación realmente detecte una inconsistencia. Ejecutar:
SET client_min_messages = DEBUG1;
en una sesión interactiva de psql antes de ejecutar una consulta de verificación mostrará mensajes sobre el progreso de la verificación con un nivel de detalle manejable.
verify_heapam(relation regclass,
on_error_stop boolean,
check_toast boolean,
skip text,
startblock bigint,
endblock bigint,
blkno OUT bigint,
offnum OUT integer,
attnum OUT integer,
msg OUT text)
returns setof record
Comprueba una tabla, secuencia o vista materializada en busca de corrupción estructural, donde las páginas de la relación contienen datos con un formato no válido, y en busca de corrupción lógica, donde las páginas son estructuralmente válidas pero inconsistentes con el resto del clúster de la base de datos.
Se admiten los siguientes argumentos opcionales:
on_error_stopSi es true, la comprobación de corrupción se detiene al final del primer bloque en el que se encuentre cualquier corrupción.
Por defecto es false.
check_toastSi es true, los valores TOAST se comprueban con la tabla TOAST de la relación objetivo.
Se sabe que esta opción es lenta. Además, si la tabla TOAST o su índice están corruptos, comprobarla con los valores TOAST podría provocar la caída del servidor, aunque en muchos casos esto solo produciría un error.
Por defecto es false.
skip
Si no es none, la comprobación de corrupción omite los bloques marcados como
all-visible (completamente visibles) o all-frozen (completamente congelados), según se especifique.
Las opciones válidas son all-visible, all-frozen y
none.
Por defecto es none.
startblock
Si se especifica, la comprobación de corrupción comienza en el bloque especificado, omitiendo
todos los bloques anteriores. Es un error especificar un startblock
fuera del rango de bloques en la tabla objetivo.
Por defecto, la comprobación comienza en el primer bloque.
endblock
Si se especifica, la comprobación de corrupción finaliza en el bloque especificado, omitiendo
todos los bloques restantes. Es un error especificar un endblock
fuera del rango de bloques en la tabla objetivo.
Por defecto, se comprueban todos los bloques.
Para cada corrupción detectada, verify_heapam devuelve una fila con
las siguientes columnas:
blknoEl número del bloque que contiene la página corrupta.
offnumEl OffsetNumber de la tupla corrupta.
attnumEl número de atributo de la columna corrupta en la tupla, si la corrupción es específica de una columna y no de la tupla en su conjunto.
msgUn mensaje que describe el problema detectado.
heapallindexed #
Cuando el argumento heapallindexed de las funciones de verificación
de B-Tree es true, se realiza una fase adicional de verificación contra la
tabla asociada con la relación del índice objetivo. Esto consiste en una operación
“ficticia” (dummy) de CREATE INDEX CONCURRENTLY, que comprueba la
presencia de todas las hipotéticas nuevas tuplas de índice frente a una estructura de resumen
temporal en memoria (esta se construye cuando es necesario durante la primera fase básica de
verificación). La estructura de resumen “registra la huella digital” (fingerprint)
de cada tupla encontrada dentro del índice objetivo. El principio de alto nivel detrás de la
verificación heapallindexed es que un nuevo índice que es equivalente
al índice objetivo existente solo debe tener entradas que se puedan encontrar en la estructura existente.
La fase adicional heapallindexed añade una sobrecarga significativa:
la verificación normalmente tardará varias veces más. Sin embargo, no hay cambios en los bloqueos a
nivel de relación adquiridos cuando se realiza la verificación heapallindexed.
La estructura de resumen está limitada en tamaño por maintenance_work_mem.
Para garantizar que no haya más de un 2% de probabilidad de no detectar una inconsistencia por
cada tupla de montón que debería estar representada en el índice, se necesitan aproximadamente
2 bytes de memoria por tupla. A medida que se dispone de menos memoria por tupla, la probabilidad de
pasar por alto una inconsistencia aumenta lentamente. Este enfoque limita significativamente la sobrecarga
de la verificación, al tiempo que reduce solo ligeramente la probabilidad de detectar un problema,
especialmente para las instalaciones donde la verificación se trata como una tarea de mantenimiento
rutinaria. Cualquier tupla ausente o mal formada tiene una nueva oportunidad de ser detectada con cada
nuevo intento de verificación.
amcheck #
amcheck puede ser eficaz para detectar varios tipos de modos de fallo
que las sumas de comprobación de datos (data checksums)
no lograrán capturar. Estos incluyen:
Inconsistencias estructurales causadas por implementaciones incorrectas de clases de operadores.
Esto incluye problemas causados por cambios en las reglas de comparación de las colaciones del
sistema operativo. Las comparaciones de datos de un tipo con colación (como text)
deben ser inmutables (al igual que todas las comparaciones utilizadas para los escaneos de índices
B-Tree deben ser inmutables), lo que implica que las reglas de colación del sistema operativo nunca
deben cambiar. Aunque es poco común, las actualizaciones de las reglas de colación del sistema
operativo pueden causar estos problemas. Más comúnmente, se implica una inconsistencia en el orden
de colación entre un servidor primario y un servidor en espera (standby), posiblemente porque la versión
mayor del sistema operativo en uso es inconsistente. Tales inconsistencias generalmente
solo surgirán en servidores en espera y, por lo tanto, generalmente solo se pueden detectar en servidores
en espera.
Si surge un problema como este, es posible que no afecte a cada índice individual ordenado utilizando una colación afectada, simplemente porque los valores indexados podrían tener el mismo orden absoluto independientemente de la inconsistencia de comportamiento. Consulta el Section 23.1 y el Section 23.2 para obtener más detalles sobre cómo PostgreSQL utiliza los locales y las colaciones del sistema operativo.
Inconsistencias estructurales entre los índices y las relaciones de montón que están indexadas (cuando
se realiza la verificación heapallindexed).
No hay una comprobación cruzada de los índices con su relación de montón durante el funcionamiento normal. Los síntomas de la corrupción del montón pueden ser sutiles.
Corrupción causada por errores hipotéticos no descubiertos en el código del método de acceso, código de ordenamiento o código de gestión de transacciones subyacente de PostgreSQL.
La verificación automática de la integridad estructural de los índices juega un papel en las pruebas
generales de las características nuevas o propuestas de PostgreSQL que podrían
permitir de manera plausible que se introduzca una inconsistencia lógica. La verificación de la estructura
de la tabla y la información asociada sobre la visibilidad y el estado de las transacciones juega un papel
similar. Una estrategia de prueba obvia es llamar a las funciones de amcheck continuamente
cuando se ejecutan las pruebas de regresión estándar. Consulta el Section 31.1 para obtener
detalles sobre cómo ejecutar las pruebas.
Fallos del sistema de archivos o del subsistema de almacenamiento cuando las sumas de comprobación de datos están deshabilitadas.
Ten en cuenta que amcheck examina una página tal como se representa en algún búfer de
memoria compartida en el momento de la verificación si solo hay un acierto de búfer compartido al acceder al
bloque. Por consiguiente, amcheck no examina necesariamente los datos leídos del sistema
de archivos en el momento de la verificación. Ten en cuenta que cuando las sumas de comprobación están
habilitadas, amcheck puede generar un error debido a un fallo de suma de comprobación
cuando se lee un bloque corrupto en un búfer.
Corrupción causada por RAM defectuosa, o por el subsistema de memoria en general.
PostgreSQL no protege contra errores de memoria corregibles y se asume que operarás utilizando RAM que utilice códigos de corrección de errores (ECC) estándar de la industria o una protección mejor. Sin embargo, la memoria ECC normalmente solo es inmune a errores de un solo bit, y no debe asumirse que proporciona una protección absoluta contra fallos que resulten en la corrupción de la memoria.
Cuando se realiza la verificación heapallindexed, generalmente hay una probabilidad mucho mayor
de detectar errores de un solo bit, ya que se prueba la igualdad binaria estricta y se prueban los atributos
indexados dentro del montón.
La corrupción estructural puede ocurrir debido a hardware de almacenamiento defectuoso, o a que los archivos de relación sean sobrescritos o modificados por software no relacionado. Este tipo de corrupción también se puede detectar con las sumas de comprobación de páginas de datos (data page checksums).
Las páginas de relación que están correctamente formateadas, son internamente consistentes y correctas con respecto a sus propias sumas de comprobación internas aún pueden contener corrupción lógica. Como tal, este tipo de corrupción no se puede detectar con las sumas de comprobación. Los ejemplos incluyen valores TOAST en la tabla principal que carecen de una entrada correspondiente en la tabla TOAST, y tuplas en la tabla principal con un ID de transacción que es anterior al ID de transacción válido más antiguo en la base de datos o clúster.
Se han observado múltiples causas de corrupción lógica en sistemas de producción, incluyendo errores en el software del servidor PostgreSQL, herramientas de copia de seguridad y restauración defectuosas y mal concebidas, y errores del usuario.
Las relaciones corruptas son de lo más preocupante en los entornos de producción en vivo, precisamente los mismos entornos
donde las actividades de alto riesgo son menos bienvenidas. Por esta razón, verify_heapam ha sido
diseñada para diagnosticar la corrupción sin riesgos indebidos. No puede proteger contra todas las causas de caídas del
backend, ya que incluso ejecutar la consulta que la llama podría ser inseguro en un sistema gravemente corrupto. El acceso a las
tablas de catálogo se realiza y podría ser problemático si los propios catálogos
están corruptos.
En general, amcheck solo puede probar la presencia de corrupción; no puede probar su ausencia.
Ningún error relativo a corrupción detectado por amcheck debería ser jamás un falso positivo.
amcheck genera errores en caso de condiciones que, por definición, nunca deberían ocurrir,
por lo que a menudo se requiere un análisis cuidadoso de los errores de amcheck.
No existe un método general para reparar los problemas que detecta amcheck. Se debe buscar una
explicación de la causa raíz de la violación del invariante. El módulo pageinspect puede desempeñar un
papel útil en el diagnóstico de la corrupción que detecta amcheck. Un comando REINDEX
puede no ser eficaz para reparar la corrupción.