-- $NetBSD: check.sql,v 1.1 2011/10/12 01:05:00 yamt Exp $
-- Copyright (c)2010,2011 YAMAMOTO Takashi,
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions
-- are met:
-- 1. Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
--
-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-- SUCH DAMAGE.
-- filesystem consistency checks. ie. something like "fsck -n"
BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET TRANSACTION READ ONLY;
SET search_path TO pgfs;
SELECT count(*) AS "unreferenced files (dirent)"
FROM file f LEFT JOIN dirent d
ON f.fileid = d.child_fileid
WHERE f.fileid <> 1 AND d.child_fileid IS NULL;
SELECT count(*) AS "unreferenced files (nlink)"
FROM file f
WHERE f.nlink = 0;
SELECT count(*) AS "regular files without datafork"
FROM file f LEFT JOIN datafork df
ON f.fileid = df.fileid
WHERE df.fileid IS NULL AND f.type IN ('regular', 'link');
SELECT count(*) AS "broken datafork reference"
FROM file f INNER JOIN datafork df
ON f.fileid = df.fileid
WHERE f.type NOT IN ('regular', 'link');
SELECT count(*) AS "unreferenced dataforks"
FROM file f RIGHT JOIN datafork df
ON f.fileid = df.fileid
WHERE f.fileid IS NULL;
SELECT count(*) AS "dataforks without large object"
FROM datafork df LEFT JOIN pg_largeobject_metadata lm
ON df.loid = lm.oid
WHERE lm.oid IS NULL;
SELECT count(*) AS "unreferenced large objects"
FROM datafork df RIGHT JOIN pg_largeobject_metadata lm
ON df.loid = lm.oid
WHERE df.loid IS NULL;
SELECT count(*) AS "dirent broken parent_fileid references"
FROM dirent d LEFT JOIN file f
ON d.parent_fileid = f.fileid
WHERE f.fileid IS NULL OR f.type <> 'directory';
SELECT count(*) AS "dirent broken child_fileid references"
FROM dirent d LEFT JOIN file f
ON d.child_fileid = f.fileid
WHERE f.fileid IS NULL;
SELECT count(*) AS "dirent loops" FROM file f WHERE EXISTS (
WITH RECURSIVE r AS
(
SELECT d.* FROM dirent d
WHERE d.child_fileid = f.fileid
UNION ALL
SELECT d.* FROM dirent d INNER JOIN r
ON d.child_fileid = r.parent_fileid
)
SELECT * FROM r WHERE r.parent_fileid = f.fileid);
SELECT count(*) AS "broken nlink"
FROM
(
SELECT coalesce(fp.fileid, fc.fileid) AS fileid,
coalesce(fp.nlink, 0) + coalesce(fc.nlink, 0) +
CASE
WHEN coalesce(fp.fileid, fc.fileid) = 1 THEN 1
ELSE 0
END
AS nlink
FROM
(
SELECT child_fileid AS fileid, count(*) AS nlink
FROM dirent
GROUP BY child_fileid
) fp
FULL JOIN
(
SELECT count(*) AS nlink, d.parent_fileid AS fileid
FROM dirent d
JOIN file f
ON d.child_fileid = f.fileid
WHERE f.type = 'directory'
GROUP BY parent_fileid
) fc
ON fp.fileid = fc.fileid
) d
FULL JOIN file f
ON d.fileid = f.fileid
WHERE (d.nlink IS NULL AND (f.fileid <> 1 AND f.nlink <> 0))
OR f.nlink IS NULL
OR d.nlink <> f.nlink;
COMMIT;