Monday, March 19, 2018

Decoding files with pg_filenodemapdata

From time to time, you may need to figure out which file in a PostgreSQL data directory corresponds to a particular table or index in the database. For example, pg_hexedit users sometimes need this information, since pg_hexedit is a frontend utility that works by reading relation files from the filesystem. In practice, a pg_hexedit convenience script can usually be used instead. Users need only give the name of the table or index that is to be examined. The convenience scripts call the built-in function pg_relation_filepath() via an SQL query.

This approach won't always work, though. pg_hexedit is a tool for investigating corruption, and sometimes corruption can affect system catalogs in a way that makes it impossible to even establish a connection to the database. You may find that you're greeted with an arcane error any time you attempt to connect to the database. The error may look something like this:

ERROR:  catalog is missing 3 attribute(s) for relid 827

In this example, the issue that prevents us from connecting must have something to do with the system catalog pg_attribute, and/or an index on pg_attribute. The catalog with relid/pg_class OID 827 (pg_default_acl_role_nsp_obj_index) appears to lack pg_attribute entries, making the built-in/catalog index pg_default_acl_role_nsp_obj_index unusable (note that there is no reason to think that the underlying relfile for pg_default_acl_role_nsp_obj_index is itself corrupt). To confirm this theory, we'll need to directly examine the pg_attribute relation for the database. Of course, there is no way to query pg_attribute, because we cannot connect. Moreover, there is no easy way to know where the files associated with pg_attribute are, so that we can at least examine pg_attribute using pg_hexedit. The "relfilenode" number that corresponds to pg_attribute (or any other table) isn't hard-coded or stable. For example, the relfilenode of a table will change any time VACUUM FULL is used on the table.

I've written a tool called pg_filenodemapdata that can help when something like this happens. This new pg_hexedit-bundled program prints the contents of files. It can be used to determine the relfilenode numbers that correspond to system catalogs entries from a file (pg_class OID to relfilenode map file). pg_attribute is an example of a special system catalog that is mapped by per-database files. As a rule of thumb, the most severe system catalog corruption is corruption that affects one of the catalogs that Postgres tracks within a file. pg_filenodemapdata should help with getting to the bottom of the problem; it's now possible to at least examine the corrupt pg_attribute file.

No comments:

Post a Comment