1-- $NetBSD: check.sql,v 1.1 2011/10/12 01:05:00 yamt Exp $
2
3-- Copyright (c)2010,2011 YAMAMOTO Takashi,
4-- All rights reserved.
5--
6-- Redistribution and use in source and binary forms, with or without
7-- modification, are permitted provided that the following conditions
8-- are met:
9-- 1. Redistributions of source code must retain the above copyright
10--    notice, this list of conditions and the following disclaimer.
11-- 2. Redistributions in binary form must reproduce the above copyright
12--    notice, this list of conditions and the following disclaimer in the
13--    documentation and/or other materials provided with the distribution.
14--
15-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18-- ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25-- SUCH DAMAGE.
26
27-- filesystem consistency checks.  ie. something like "fsck -n"
28
29BEGIN;
30SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
31SET TRANSACTION READ ONLY;
32SET search_path TO pgfs;
33SELECT count(*) AS "unreferenced files (dirent)"
34          FROM file f LEFT JOIN dirent d
35          ON f.fileid = d.child_fileid
36          WHERE f.fileid <> 1 AND d.child_fileid IS NULL;
37SELECT count(*) AS "unreferenced files (nlink)"
38          FROM file f
39          WHERE f.nlink = 0;
40SELECT count(*) AS "regular files without datafork"
41          FROM file f LEFT JOIN datafork df
42          ON f.fileid = df.fileid
43          WHERE df.fileid IS NULL AND f.type IN ('regular', 'link');
44SELECT count(*) AS "broken datafork reference"
45          FROM file f INNER JOIN datafork df
46          ON f.fileid = df.fileid
47          WHERE f.type NOT IN ('regular', 'link');
48SELECT count(*) AS "unreferenced dataforks"
49          FROM file f RIGHT JOIN datafork df
50          ON f.fileid = df.fileid
51          WHERE f.fileid IS NULL;
52SELECT count(*) AS "dataforks without large object"
53          FROM datafork df LEFT JOIN pg_largeobject_metadata lm
54          ON df.loid = lm.oid
55          WHERE lm.oid IS NULL;
56SELECT count(*) AS "unreferenced large objects"
57          FROM datafork df RIGHT JOIN pg_largeobject_metadata lm
58          ON df.loid = lm.oid
59          WHERE df.loid IS NULL;
60SELECT count(*) AS "dirent broken parent_fileid references"
61          FROM dirent d LEFT JOIN file f
62          ON d.parent_fileid = f.fileid
63          WHERE f.fileid IS NULL OR f.type <> 'directory';
64SELECT count(*) AS "dirent broken child_fileid references"
65          FROM dirent d LEFT JOIN file f
66          ON d.child_fileid = f.fileid
67          WHERE f.fileid IS NULL;
68SELECT count(*) AS "dirent loops" FROM file f WHERE EXISTS (
69          WITH RECURSIVE r AS
70          (
71                              SELECT d.* FROM dirent d
72                                        WHERE d.child_fileid = f.fileid
73                    UNION ALL
74                              SELECT d.* FROM dirent d INNER JOIN r
75                                        ON d.child_fileid = r.parent_fileid
76          )
77          SELECT * FROM r WHERE r.parent_fileid = f.fileid);
78SELECT count(*) AS "broken nlink"
79          FROM
80          (
81          SELECT coalesce(fp.fileid, fc.fileid) AS fileid,
82                    coalesce(fp.nlink, 0) + coalesce(fc.nlink, 0) +
83                    CASE
84                              WHEN coalesce(fp.fileid, fc.fileid) = 1 THEN 1
85                              ELSE 0
86                    END
87                    AS nlink
88                    FROM
89                    (
90                    SELECT child_fileid AS fileid, count(*) AS nlink
91                              FROM dirent
92                              GROUP BY child_fileid
93                    ) fp
94                    FULL JOIN
95                    (
96                    SELECT count(*) AS nlink, d.parent_fileid AS fileid
97                              FROM dirent d
98                              JOIN file f
99                              ON d.child_fileid = f.fileid
100                              WHERE f.type = 'directory'
101                              GROUP BY parent_fileid
102                    ) fc
103                    ON fp.fileid = fc.fileid
104          ) d
105          FULL JOIN file f
106          ON d.fileid = f.fileid
107          WHERE (d.nlink IS NULL AND (f.fileid <> 1 AND f.nlink <> 0))
108              OR f.nlink IS NULL
109              OR d.nlink <> f.nlink;
110COMMIT;
111