mirror of https://github.com/postgres/postgres
pg_tablespace_size pg_database_size pg_relation_size pg_complete_relation_size pg_size_pretty Remove /contrib/dbsize. Dave PageREL8_1_STABLE
parent
b05801c828
commit
358a897fa1
@ -1,13 +0,0 @@ |
||||
MODULES = dbsize
|
||||
DATA_built = dbsize.sql
|
||||
DOCS = README.dbsize
|
||||
|
||||
ifdef USE_PGXS |
||||
PGXS = $(shell pg_config --pgxs)
|
||||
include $(PGXS) |
||||
else |
||||
subdir = contrib/dbsize
|
||||
top_builddir = ../..
|
||||
include $(top_builddir)/src/Makefile.global |
||||
include $(top_srcdir)/contrib/contrib-global.mk |
||||
endif |
||||
@ -1,115 +0,0 @@ |
||||
This module contains several functions that report the on-disk size of a |
||||
given database object in bytes: |
||||
|
||||
int8 database_size(name) |
||||
int8 relation_size(text) |
||||
int8 indexes_size(text) |
||||
int8 total_relation_size(text) |
||||
|
||||
int8 pg_database_size(oid) |
||||
int8 pg_relation_size(oid) |
||||
int8 pg_tablespace_size(oid) |
||||
|
||||
text pg_size_pretty(int8) |
||||
|
||||
setof record relation_size_components(text) |
||||
|
||||
The first four functions take the name of the object (possibly |
||||
schema-qualified for the latter three) and returns the size of the |
||||
on-disk files in bytes. |
||||
|
||||
SELECT database_size('template1'); |
||||
SELECT relation_size('pg_class'); |
||||
SELECT indexes_size('pg_class'); |
||||
SELECT total_relation_size('pg_class'); |
||||
|
||||
These functions take object OIDs: |
||||
|
||||
SELECT pg_database_size(1); -- template1 database |
||||
SELECT pg_relation_size(1259); -- pg_class table size |
||||
SELECT pg_tablespace_size(1663); -- pg_default tablespace |
||||
|
||||
The indexes_size() function returns the total size of the indices for a |
||||
relation, including any toasted indices. |
||||
|
||||
The total_relation_size() function returns the total size of the relation, |
||||
all its indices, and any toasted data. |
||||
|
||||
Please note that relation_size and pg_relation_size report only the size of |
||||
the selected relation itself; any related indexes or toast tables are not |
||||
counted. To obtain the total size of a table including all indices and |
||||
toasted data, use total_relation_size(). |
||||
|
||||
The last function, relation_size_components(), returns a set of rows |
||||
showing the sizes of the component relations constituting the input |
||||
relation. |
||||
|
||||
Examples |
||||
======== |
||||
|
||||
I've loaded the following table with a little less than 3 MB of data for |
||||
illustration: |
||||
|
||||
create table fat ( id serial, data varchar ); |
||||
create index fat_uidx on fat (id); |
||||
create index fat_idx on fat (data); |
||||
|
||||
You can retrieve a rowset containing constituent sizes as follows: |
||||
|
||||
# SELECT relation_size_components('fat'); |
||||
relation_size_components |
||||
---------------------------------------------------- |
||||
(2088960,65536,2891776,fat,r,59383,59383) |
||||
(32768,704512,737280,pg_toast_59383,t,59386,59386) |
||||
(0,32768,32768,pg_toast_59383_index,i,59388,59388) |
||||
(0,2039808,2039808,fat_idx,i,59389,59389) |
||||
(0,49152,49152,fat_uidx,i,59911,59911) |
||||
(5 rows) |
||||
|
||||
To see a more readable output of the rowset: |
||||
|
||||
SELECT * |
||||
FROM relation_size_components('fat') AS (idxsize BIGINT, |
||||
datasize BIGINT, |
||||
totalsize BIGINT, |
||||
relname NAME, |
||||
kind "char", |
||||
relid OID, |
||||
node OID) |
||||
ORDER BY totalsize; |
||||
|
||||
idxsize | datasize | totalsize | relname | kind | relid | node |
||||
---------+----------+-----------+----------------------+------+-------+------- |
||||
0 | 32768 | 32768 | pg_toast_59383_index | i | 59388 | 59388 |
||||
0 | 49152 | 49152 | fat_uidx | i | 59911 | 59911 |
||||
32768 | 704512 | 737280 | pg_toast_59383 | t | 59386 | 59386 |
||||
0 | 2039808 | 2039808 | fat_idx | i | 59389 | 59389 |
||||
2088960 | 65536 | 2891776 | fat | r | 59383 | 59383 |
||||
(5 rows) |
||||
|
||||
To see the sum total size of a relation: |
||||
|
||||
# select total_relation_size('fat'); |
||||
total_relation_size |
||||
------------------------- |
||||
2891776 |
||||
(1 row) |
||||
|
||||
To see just the size of the uncompressed relation data: |
||||
|
||||
# select relation_size('fat'); |
||||
relation_size |
||||
--------------- |
||||
65536 |
||||
(1 row) |
||||
|
||||
To see the size of all related indices: |
||||
|
||||
# select indexes_size('fat'); |
||||
indexes_size |
||||
-------------- |
||||
2088960 |
||||
(1 row) |
||||
|
||||
To install, just run make; make install. Then load the functions |
||||
into any database using dbsize.sql. |
||||
@ -1,132 +0,0 @@ |
||||
CREATE FUNCTION database_size (name) RETURNS bigint |
||||
AS 'MODULE_PATHNAME', 'database_size' |
||||
LANGUAGE C STRICT; |
||||
|
||||
CREATE FUNCTION relation_size (text) RETURNS bigint |
||||
AS 'MODULE_PATHNAME', 'relation_size' |
||||
LANGUAGE C STRICT; |
||||
|
||||
CREATE FUNCTION pg_tablespace_size(oid) RETURNS bigint |
||||
AS 'MODULE_PATHNAME', 'pg_tablespace_size' |
||||
LANGUAGE C STRICT; |
||||
|
||||
CREATE FUNCTION pg_database_size(oid) RETURNS bigint |
||||
AS 'MODULE_PATHNAME', 'pg_database_size' |
||||
LANGUAGE C STRICT; |
||||
|
||||
CREATE FUNCTION pg_relation_size(oid) RETURNS bigint |
||||
AS 'MODULE_PATHNAME', 'pg_relation_size' |
||||
LANGUAGE C STRICT; |
||||
|
||||
CREATE FUNCTION pg_size_pretty(bigint) RETURNS text |
||||
AS 'MODULE_PATHNAME', 'pg_size_pretty' |
||||
LANGUAGE C STRICT; |
||||
|
||||
CREATE FUNCTION total_relation_size (text) RETURNS bigint AS ' |
||||
SELECT pg_relation_size(r.oid) |
||||
+ COALESCE(pg_relation_size(t.oid), 0)::bigint |
||||
+ COALESCE(pg_relation_size(ti.oid), 0)::bigint |
||||
+ COALESCE(SUM(pg_relation_size(i.indexrelid)), 0)::bigint |
||||
+ COALESCE(SUM(pg_relation_size(it.oid)), 0)::bigint |
||||
+ COALESCE(SUM(pg_relation_size(iti.oid)), 0)::bigint AS bytes |
||||
FROM pg_class r |
||||
LEFT JOIN pg_class t ON (r.reltoastrelid = t.oid) |
||||
LEFT JOIN pg_class ti ON (t.reltoastidxid = ti.oid) |
||||
LEFT JOIN pg_index i ON (r.oid = i.indrelid) |
||||
LEFT JOIN pg_class ir ON (ir.oid = i.indexrelid) |
||||
LEFT JOIN pg_class it ON (ir.reltoastrelid = it.oid) |
||||
LEFT JOIN pg_class iti ON (it.reltoastidxid = iti.oid) |
||||
WHERE r.relname = \$1 |
||||
GROUP BY r.oid, t.oid, ti.oid |
||||
' LANGUAGE SQL; |
||||
|
||||
CREATE FUNCTION indexes_size (text) RETURNS bigint |
||||
AS ' |
||||
SELECT COALESCE(SUM(pg_relation_size(ir.oid)), 0)::bigint |
||||
+ COALESCE(SUM(pg_relation_size(it.oid)), 0)::bigint |
||||
+ COALESCE(SUM(pg_relation_size(iti.oid)), 0)::bigint AS bytes |
||||
FROM pg_class r |
||||
LEFT JOIN pg_index i ON (r.oid = i.indrelid) |
||||
LEFT JOIN pg_class ir ON (ir.oid = i.indexrelid) |
||||
LEFT JOIN pg_class it ON (ir.reltoastrelid = it.oid) |
||||
LEFT JOIN pg_class iti ON (it.reltoastidxid = iti.oid) |
||||
WHERE r.relname = \$1 |
||||
' LANGUAGE SQL; |
||||
|
||||
CREATE FUNCTION relation_size_components (text) RETURNS SETOF RECORD |
||||
AS ' |
||||
-- relation size |
||||
SELECT indexes_size(r.relname) AS indexes_size, |
||||
relation_size(r.relname) AS data_size, |
||||
total_relation_size(r.relname) AS total_size, |
||||
r.relname, r.relkind, r.oid AS relid, r.relfilenode |
||||
FROM pg_class r |
||||
WHERE r.relname = \$1 |
||||
|
||||
UNION ALL |
||||
|
||||
-- relation toast size |
||||
SELECT indexes_size(toast.relname) AS indexes_size, |
||||
relation_size(''pg_toast.''||toast.relname) AS data_size, |
||||
total_relation_size(toast.relname) AS total_size, |
||||
toast.relname, toast.relkind, toast.oid AS relid, toast.relfilenode |
||||
FROM pg_class r, pg_class toast |
||||
WHERE r.reltoastrelid = toast.oid |
||||
AND r.relname = \$1 |
||||
|
||||
UNION ALL |
||||
|
||||
-- relation toast index size |
||||
SELECT indexes_size(toastidxr.relname) AS indexes_size, |
||||
relation_size(''pg_toast.''||toastidxr.relname) AS data_size, |
||||
total_relation_size(toastidxr.relname) AS total_size, |
||||
toastidxr.relname, toastidxr.relkind, |
||||
toastidxr.oid AS relid, toastidxr.relfilenode |
||||
FROM pg_class r, pg_index toastidx, pg_class toastidxr |
||||
WHERE r.relname = \$1 |
||||
AND r.reltoastrelid = toastidx.indrelid |
||||
AND toastidx.indexrelid = toastidxr.oid |
||||
|
||||
UNION ALL |
||||
|
||||
-- relation indices size |
||||
SELECT indexes_size(idxr.relname) AS indexes_size, |
||||
relation_size(idxr.relname) AS data_size, |
||||
total_relation_size(idxr.relname) AS total_size, |
||||
idxr.relname, idxr.relkind, idxr.oid AS relid, idxr.relfilenode |
||||
FROM pg_class r, pg_class idxr, pg_index idx |
||||
WHERE r.relname = \$1 |
||||
AND r.oid = idx.indrelid |
||||
AND idx.indexrelid = idxr.oid |
||||
|
||||
UNION ALL |
||||
|
||||
-- relation indices toast size |
||||
SELECT indexes_size(idxtoastr.relname) AS indexes_size, |
||||
relation_size(''pg_toast.''||idxtoastr.relname) AS data_size, |
||||
total_relation_size(idxtoastr.relname) AS total_size, |
||||
idxtoastr.relname, idxtoastr.relkind, idxtoastr.oid AS relid, |
||||
idxtoastr.relfilenode |
||||
FROM pg_class r, pg_class idxr, pg_index idx, pg_class idxtoastr |
||||
WHERE r.relname = \$1 |
||||
AND r.oid = idx.indrelid |
||||
AND idx.indexrelid = idxr.oid |
||||
AND idxr.reltoastrelid = idxtoastr.oid |
||||
|
||||
UNION ALL |
||||
|
||||
-- relation indices toast index size |
||||
SELECT indexes_size(idxtoastidxr.relname) AS indexes_size, |
||||
relation_size(''pg_toast.''||idxtoastidxr.relname) AS data_size, |
||||
total_relation_size(idxtoastidxr.relname) AS total_size, |
||||
idxtoastidxr.relname, idxtoastidxr.relkind, |
||||
idxtoastidxr.oid AS relid, idxtoastidxr.relfilenode |
||||
FROM pg_class r, pg_class idxr, pg_index idx, pg_class idxtoast, |
||||
pg_class idxtoastidxr |
||||
WHERE r.relname = \$1 |
||||
AND r.oid = idx.indrelid |
||||
AND idx.indexrelid = idxr.oid |
||||
AND idxr.reltoastrelid = idxtoast.oid |
||||
AND idxtoast.reltoastrelid = idxtoastidxr.oid |
||||
' LANGUAGE SQL; |
||||
|
||||
@ -1,335 +1,461 @@ |
||||
/*
|
||||
* dbsize.c |
||||
* object size functions |
||||
* |
||||
* Copyright (c) 2002-2005, PostgreSQL Global Development Group |
||||
* |
||||
* IDENTIFICATION |
||||
* $PostgreSQL: pgsql/contrib/dbsize/dbsize.c,v 1.19 2005/07/04 04:51:43 tgl Exp $ |
||||
* |
||||
*/ |
||||
|
||||
#include "postgres.h" |
||||
|
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
|
||||
#include "access/heapam.h" |
||||
#include "catalog/namespace.h" |
||||
#include "catalog/pg_tablespace.h" |
||||
#include "commands/dbcommands.h" |
||||
#include "miscadmin.h" |
||||
#include "storage/fd.h" |
||||
#include "utils/builtins.h" |
||||
#include "utils/syscache.h" |
||||
|
||||
|
||||
Datum pg_tablespace_size(PG_FUNCTION_ARGS); |
||||
Datum pg_database_size(PG_FUNCTION_ARGS); |
||||
Datum pg_relation_size(PG_FUNCTION_ARGS); |
||||
Datum pg_size_pretty(PG_FUNCTION_ARGS); |
||||
|
||||
Datum database_size(PG_FUNCTION_ARGS); |
||||
Datum relation_size(PG_FUNCTION_ARGS); |
||||
|
||||
PG_FUNCTION_INFO_V1(pg_tablespace_size); |
||||
PG_FUNCTION_INFO_V1(pg_database_size); |
||||
PG_FUNCTION_INFO_V1(pg_relation_size); |
||||
PG_FUNCTION_INFO_V1(pg_size_pretty); |
||||
|
||||
PG_FUNCTION_INFO_V1(database_size); |
||||
PG_FUNCTION_INFO_V1(relation_size); |
||||
|
||||
|
||||
/* Return physical size of directory contents, or 0 if dir doesn't exist */ |
||||
static int64 |
||||
db_dir_size(const char *path) |
||||
{ |
||||
int64 dirsize = 0; |
||||
struct dirent *direntry; |
||||
DIR *dirdesc; |
||||
char filename[MAXPGPATH]; |
||||
|
||||
dirdesc = AllocateDir(path); |
||||
|
||||
if (!dirdesc) |
||||
return 0; |
||||
|
||||
while ((direntry = ReadDir(dirdesc, path)) != NULL) |
||||
{ |
||||
struct stat fst; |
||||
|
||||
if (strcmp(direntry->d_name, ".") == 0 || |
||||
strcmp(direntry->d_name, "..") == 0) |
||||
continue; |
||||
|
||||
snprintf(filename, MAXPGPATH, "%s/%s", path, direntry->d_name); |
||||
|
||||
if (stat(filename, &fst) < 0) |
||||
ereport(ERROR, |
||||
(errcode_for_file_access(), |
||||
errmsg("could not stat \"%s\": %m", filename))); |
||||
dirsize += fst.st_size; |
||||
} |
||||
|
||||
FreeDir(dirdesc); |
||||
return dirsize; |
||||
} |
||||
|
||||
|
||||
static int64 |
||||
calculate_database_size(Oid dbOid) |
||||
{ |
||||
int64 totalsize = 0; |
||||
DIR *dirdesc; |
||||
struct dirent *direntry; |
||||
char pathname[MAXPGPATH]; |
||||
|
||||
/* Shared storage in pg_global is not counted */ |
||||
|
||||
/* Include pg_default storage */ |
||||
snprintf(pathname, MAXPGPATH, "base/%u", dbOid); |
||||
totalsize += db_dir_size(pathname); |
||||
|
||||
/* Scan the non-default tablespaces */ |
||||
snprintf(pathname, MAXPGPATH, "pg_tblspc"); |
||||
dirdesc = AllocateDir(pathname); |
||||
|
||||
while ((direntry = ReadDir(dirdesc, pathname)) != NULL) |
||||
{ |
||||
if (strcmp(direntry->d_name, ".") == 0 || |
||||
strcmp(direntry->d_name, "..") == 0) |
||||
continue; |
||||
|
||||
snprintf(pathname, MAXPGPATH, "pg_tblspc/%s/%u", |
||||
direntry->d_name, dbOid); |
||||
totalsize += db_dir_size(pathname); |
||||
} |
||||
|
||||
FreeDir(dirdesc); |
||||
|
||||
/* Complain if we found no trace of the DB at all */ |
||||
if (!totalsize) |
||||
ereport(ERROR, |
||||
(ERRCODE_UNDEFINED_DATABASE, |
||||
errmsg("database with OID %u does not exist", dbOid))); |
||||
|
||||
return totalsize; |
||||
} |
||||
|
||||
/*
|
||||
* calculate total size of tablespace |
||||
*/ |
||||
Datum |
||||
pg_tablespace_size(PG_FUNCTION_ARGS) |
||||
{ |
||||
Oid tblspcOid = PG_GETARG_OID(0); |
||||
char tblspcPath[MAXPGPATH]; |
||||
char pathname[MAXPGPATH]; |
||||
int64 totalsize=0; |
||||
DIR *dirdesc; |
||||
struct dirent *direntry; |
||||
|
||||
if (tblspcOid == DEFAULTTABLESPACE_OID) |
||||
snprintf(tblspcPath, MAXPGPATH, "base"); |
||||
else if (tblspcOid == GLOBALTABLESPACE_OID) |
||||
snprintf(tblspcPath, MAXPGPATH, "global"); |
||||
else |
||||
snprintf(tblspcPath, MAXPGPATH, "pg_tblspc/%u", tblspcOid); |
||||
|
||||
dirdesc = AllocateDir(tblspcPath); |
||||
|
||||
while ((direntry = ReadDir(dirdesc, tblspcPath)) != NULL) |
||||
{ |
||||
struct stat fst; |
||||
|
||||
if (strcmp(direntry->d_name, ".") == 0 || |
||||
strcmp(direntry->d_name, "..") == 0) |
||||
continue; |
||||
|
||||
snprintf(pathname, MAXPGPATH, "%s/%s", tblspcPath, direntry->d_name); |
||||
|
||||
if (stat(pathname, &fst) < 0) |
||||
ereport(ERROR, |
||||
(errcode_for_file_access(), |
||||
errmsg("could not stat \"%s\": %m", pathname))); |
||||
totalsize += fst.st_size; |
||||
|
||||
if (fst.st_mode & S_IFDIR) |
||||
totalsize += db_dir_size(pathname); |
||||
} |
||||
|
||||
FreeDir(dirdesc); |
||||
|
||||
PG_RETURN_INT64(totalsize); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* calculate size of database in all tablespaces |
||||
*/ |
||||
Datum |
||||
pg_database_size(PG_FUNCTION_ARGS) |
||||
{ |
||||
Oid dbOid = PG_GETARG_OID(0); |
||||
|
||||
PG_RETURN_INT64(calculate_database_size(dbOid)); |
||||
} |
||||
|
||||
Datum |
||||
database_size(PG_FUNCTION_ARGS) |
||||
{ |
||||
Name dbName = PG_GETARG_NAME(0); |
||||
Oid dbOid = get_database_oid(NameStr(*dbName)); |
||||
|
||||
if (!OidIsValid(dbOid)) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_UNDEFINED_DATABASE), |
||||
errmsg("database \"%s\" does not exist", |
||||
NameStr(*dbName)))); |
||||
|
||||
PG_RETURN_INT64(calculate_database_size(dbOid)); |
||||
} |
||||
|
||||
|
||||
/* Calculate relation size given tablespace and relation OIDs */ |
||||
static int64 |
||||
calculate_relation_size(Oid tblspcOid, Oid relnodeOid) |
||||
{ |
||||
int64 totalsize=0; |
||||
unsigned int segcount=0; |
||||
char dirpath[MAXPGPATH]; |
||||
char pathname[MAXPGPATH]; |
||||
|
||||
if (!tblspcOid) |
||||
tblspcOid = MyDatabaseTableSpace; |
||||
|
||||
if (tblspcOid == DEFAULTTABLESPACE_OID) |
||||
snprintf(dirpath, MAXPGPATH, "base/%u", MyDatabaseId); |
||||
else if (tblspcOid == GLOBALTABLESPACE_OID) |
||||
snprintf(dirpath, MAXPGPATH, "global"); |
||||
else |
||||
snprintf(dirpath, MAXPGPATH, "pg_tblspc/%u/%u", |
||||
tblspcOid, MyDatabaseId); |
||||
|
||||
for (segcount = 0 ;; segcount++) |
||||
{ |
||||
struct stat fst; |
||||
|
||||
if (segcount == 0) |
||||
snprintf(pathname, MAXPGPATH, "%s/%u", |
||||
dirpath, relnodeOid); |
||||
else |
||||
snprintf(pathname, MAXPGPATH, "%s/%u.%u", |
||||
dirpath, relnodeOid, segcount); |
||||
|
||||
if (stat(pathname, &fst) < 0) |
||||
{ |
||||
if (errno == ENOENT) |
||||
break; |
||||
else |
||||
ereport(ERROR, |
||||
(errcode_for_file_access(), |
||||
errmsg("could not stat \"%s\": %m", pathname))); |
||||
} |
||||
totalsize += fst.st_size; |
||||
} |
||||
|
||||
return totalsize; |
||||
} |
||||
|
||||
/*
|
||||
* calculate size of relation |
||||
*/ |
||||
Datum |
||||
pg_relation_size(PG_FUNCTION_ARGS) |
||||
{ |
||||
Oid relOid=PG_GETARG_OID(0); |
||||
HeapTuple tuple; |
||||
Form_pg_class pg_class; |
||||
Oid relnodeOid; |
||||
Oid tblspcOid; |
||||
|
||||
tuple = SearchSysCache(RELOID, |
||||
ObjectIdGetDatum(relOid), |
||||
0, 0, 0); |
||||
if (!HeapTupleIsValid(tuple)) |
||||
ereport(ERROR, |
||||
(ERRCODE_UNDEFINED_TABLE, |
||||
errmsg("relation with OID %u does not exist", relOid))); |
||||
|
||||
pg_class = (Form_pg_class) GETSTRUCT(tuple); |
||||
relnodeOid = pg_class->relfilenode; |
||||
tblspcOid = pg_class->reltablespace; |
||||
|
||||
ReleaseSysCache(tuple); |
||||
|
||||
PG_RETURN_INT64(calculate_relation_size(tblspcOid, relnodeOid)); |
||||
} |
||||
|
||||
Datum |
||||
relation_size(PG_FUNCTION_ARGS) |
||||
{ |
||||
text *relname = PG_GETARG_TEXT_P(0); |
||||
RangeVar *relrv; |
||||
Relation relation; |
||||
Oid relnodeOid; |
||||
Oid tblspcOid; |
||||
|
||||
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); |
||||
relation = relation_openrv(relrv, AccessShareLock); |
||||
|
||||
tblspcOid = relation->rd_rel->reltablespace; |
||||
relnodeOid = relation->rd_rel->relfilenode; |
||||
|
||||
relation_close(relation, AccessShareLock); |
||||
|
||||
PG_RETURN_INT64(calculate_relation_size(tblspcOid, relnodeOid)); |
||||
} |
||||
|
||||
/*
|
||||
* formatting with size units |
||||
*/ |
||||
Datum |
||||
pg_size_pretty(PG_FUNCTION_ARGS) |
||||
{ |
||||
int64 size=PG_GETARG_INT64(0); |
||||
char *result=palloc(50+VARHDRSZ); |
||||
int64 limit = 10*1024; |
||||
int64 mult=1; |
||||
|
||||
if (size < limit*mult) |
||||
snprintf(VARDATA(result), 50, INT64_FORMAT" bytes", |
||||
size); |
||||
else |
||||
{ |
||||
mult *= 1024; |
||||
if (size < limit*mult) |
||||
snprintf(VARDATA(result), 50, INT64_FORMAT " kB", |
||||
(size+mult/2) / mult); |
||||
else |
||||
{ |
||||
mult *= 1024; |
||||
if (size < limit*mult) |
||||
snprintf(VARDATA(result), 50, INT64_FORMAT " MB", |
||||
(size+mult/2) / mult); |
||||
else |
||||
{ |
||||
mult *= 1024; |
||||
if (size < limit*mult) |
||||
snprintf(VARDATA(result), 50, INT64_FORMAT " GB", |
||||
(size+mult/2) / mult); |
||||
else |
||||
{ |
||||
mult *= 1024; |
||||
snprintf(VARDATA(result), 50, INT64_FORMAT " TB", |
||||
(size+mult/2) / mult); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
VARATT_SIZEP(result) = strlen(VARDATA(result)) + VARHDRSZ; |
||||
|
||||
PG_RETURN_TEXT_P(result); |
||||
} |
||||
/*
|
||||
* dbsize.c |
||||
* object size functions |
||||
* |
||||
* Copyright (c) 2002-2005, PostgreSQL Global Development Group |
||||
* |
||||
* IDENTIFICATION |
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/dbsize.c,v 1.1 2005/07/29 14:46:57 momjian Exp $ |
||||
* |
||||
*/ |
||||
|
||||
#include "postgres.h" |
||||
|
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
|
||||
#include "access/heapam.h" |
||||
#include "catalog/namespace.h" |
||||
#include "catalog/pg_tablespace.h" |
||||
#include "commands/dbcommands.h" |
||||
#include "commands/tablespace.h" |
||||
#include "miscadmin.h" |
||||
#include "storage/fd.h" |
||||
#include "utils/builtins.h" |
||||
#include "utils/syscache.h" |
||||
#include "utils/relcache.h" |
||||
|
||||
|
||||
/* Return physical size of directory contents, or 0 if dir doesn't exist */ |
||||
static int64 |
||||
db_dir_size(const char *path) |
||||
{ |
||||
int64 dirsize = 0; |
||||
struct dirent *direntry; |
||||
DIR *dirdesc; |
||||
char filename[MAXPGPATH]; |
||||
|
||||
dirdesc = AllocateDir(path); |
||||
|
||||
if (!dirdesc) |
||||
return 0; |
||||
|
||||
while ((direntry = readdir(dirdesc)) != NULL) |
||||
{ |
||||
struct stat fst; |
||||
|
||||
if (strcmp(direntry->d_name, ".") == 0 || |
||||
strcmp(direntry->d_name, "..") == 0) |
||||
continue; |
||||
|
||||
snprintf(filename, MAXPGPATH, "%s/%s", path, direntry->d_name); |
||||
|
||||
if (stat(filename, &fst) < 0) |
||||
ereport(ERROR, |
||||
(errcode_for_file_access(), |
||||
errmsg("could not stat \"%s\": %m", filename))); |
||||
|
||||
dirsize += fst.st_size; |
||||
} |
||||
|
||||
FreeDir(dirdesc); |
||||
return dirsize; |
||||
} |
||||
|
||||
/*
|
||||
* calculate size of database in all tablespaces |
||||
*/ |
||||
static int64 |
||||
calculate_database_size(Oid dbOid) |
||||
{ |
||||
int64 totalsize = 0; |
||||
DIR *dirdesc; |
||||
struct dirent *direntry; |
||||
char pathname[MAXPGPATH]; |
||||
|
||||
/* Shared storage in pg_global is not counted */ |
||||
|
||||
/* Include pg_default storage */ |
||||
snprintf(pathname, MAXPGPATH, "%s/base/%u", DataDir, dbOid); |
||||
totalsize += db_dir_size(pathname); |
||||
|
||||
/* Scan the non-default tablespaces */ |
||||
snprintf(pathname, MAXPGPATH, "%s/pg_tblspc", DataDir); |
||||
dirdesc = AllocateDir(pathname); |
||||
if (!dirdesc) |
||||
ereport(ERROR, |
||||
(errcode_for_file_access(), |
||||
errmsg("could not open tablespace directory \"%s\": %m", |
||||
pathname))); |
||||
|
||||
while ((direntry = readdir(dirdesc)) != NULL) |
||||
{ |
||||
if (strcmp(direntry->d_name, ".") == 0 || |
||||
strcmp(direntry->d_name, "..") == 0) |
||||
continue; |
||||
|
||||
snprintf(pathname, MAXPGPATH, "%s/pg_tblspc/%s/%u", |
||||
DataDir, direntry->d_name, dbOid); |
||||
totalsize += db_dir_size(pathname); |
||||
} |
||||
|
||||
FreeDir(dirdesc); |
||||
|
||||
/* Complain if we found no trace of the DB at all */ |
||||
if (!totalsize) |
||||
ereport(ERROR, |
||||
(ERRCODE_UNDEFINED_DATABASE, |
||||
errmsg("database with OID %u does not exist", dbOid))); |
||||
|
||||
return totalsize; |
||||
} |
||||
|
||||
Datum |
||||
pg_database_size_oid(PG_FUNCTION_ARGS) |
||||
{ |
||||
Oid dbOid = PG_GETARG_OID(0); |
||||
|
||||
PG_RETURN_INT64(calculate_database_size(dbOid)); |
||||
} |
||||
|
||||
Datum |
||||
pg_database_size_name(PG_FUNCTION_ARGS) |
||||
{ |
||||
Name dbName = PG_GETARG_NAME(0); |
||||
Oid dbOid = get_database_oid(NameStr(*dbName)); |
||||
|
||||
if (!OidIsValid(dbOid)) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_UNDEFINED_DATABASE), |
||||
errmsg("database \"%s\" does not exist", |
||||
NameStr(*dbName)))); |
||||
|
||||
PG_RETURN_INT64(calculate_database_size(dbOid)); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* calculate total size of tablespace |
||||
*/ |
||||
static int64 |
||||
calculate_tablespace_size(Oid tblspcOid) |
||||
{ |
||||
char tblspcPath[MAXPGPATH]; |
||||
char pathname[MAXPGPATH]; |
||||
int64 totalsize=0; |
||||
DIR *dirdesc; |
||||
struct dirent *direntry; |
||||
|
||||
if (tblspcOid == DEFAULTTABLESPACE_OID) |
||||
snprintf(tblspcPath, MAXPGPATH, "%s/base", DataDir); |
||||
else if (tblspcOid == GLOBALTABLESPACE_OID) |
||||
snprintf(tblspcPath, MAXPGPATH, "%s/global", DataDir); |
||||
else |
||||
snprintf(tblspcPath, MAXPGPATH, "%s/pg_tblspc/%u", DataDir, tblspcOid); |
||||
|
||||
dirdesc = AllocateDir(tblspcPath); |
||||
|
||||
if (!dirdesc) |
||||
ereport(ERROR, |
||||
(errcode_for_file_access(), |
||||
errmsg("could not open tablespace directory \"%s\": %m", |
||||
tblspcPath))); |
||||
|
||||
while ((direntry = readdir(dirdesc)) != NULL) |
||||
{ |
||||
struct stat fst; |
||||
|
||||
if (strcmp(direntry->d_name, ".") == 0 || |
||||
strcmp(direntry->d_name, "..") == 0) |
||||
continue; |
||||
|
||||
snprintf(pathname, MAXPGPATH, "%s/%s", tblspcPath, direntry->d_name); |
||||
|
||||
if (stat(pathname, &fst) < 0) |
||||
ereport(ERROR, |
||||
(errcode_for_file_access(), |
||||
errmsg("could not stat \"%s\": %m", pathname))); |
||||
|
||||
if (fst.st_mode & S_IFDIR) |
||||
totalsize += db_dir_size(pathname); |
||||
|
||||
totalsize += fst.st_size; |
||||
} |
||||
|
||||
FreeDir(dirdesc); |
||||
|
||||
return totalsize; |
||||
} |
||||
|
||||
Datum |
||||
pg_tablespace_size_oid(PG_FUNCTION_ARGS) |
||||
{ |
||||
Oid tblspcOid = PG_GETARG_OID(0); |
||||
|
||||
PG_RETURN_INT64(calculate_tablespace_size(tblspcOid)); |
||||
} |
||||
|
||||
Datum |
||||
pg_tablespace_size_name(PG_FUNCTION_ARGS) |
||||
{ |
||||
Name tblspcName = PG_GETARG_NAME(0); |
||||
Oid tblspcOid = get_tablespace_oid(NameStr(*tblspcName)); |
||||
|
||||
if (!OidIsValid(tblspcOid)) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_UNDEFINED_OBJECT), |
||||
errmsg("tablespace \"%s\" does not exist", |
||||
NameStr(*tblspcName)))); |
||||
|
||||
PG_RETURN_INT64(calculate_tablespace_size(tblspcOid)); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* calculate size of a relation |
||||
*/ |
||||
static int64 |
||||
calculate_relation_size(Oid tblspcOid, Oid relnodeOid) |
||||
{ |
||||
int64 totalsize=0; |
||||
unsigned int segcount=0; |
||||
char dirpath[MAXPGPATH]; |
||||
char pathname[MAXPGPATH]; |
||||
|
||||
if (!tblspcOid) |
||||
tblspcOid = MyDatabaseTableSpace; |
||||
|
||||
if (tblspcOid == DEFAULTTABLESPACE_OID) |
||||
snprintf(dirpath, MAXPGPATH, "%s/base/%u", DataDir, MyDatabaseId); |
||||
else if (tblspcOid == GLOBALTABLESPACE_OID) |
||||
snprintf(dirpath, MAXPGPATH, "%s/global", DataDir); |
||||
else |
||||
snprintf(dirpath, MAXPGPATH, "%s/pg_tblspc/%u/%u", |
||||
DataDir, tblspcOid, MyDatabaseId); |
||||
|
||||
for (segcount = 0 ;; segcount++) |
||||
{ |
||||
struct stat fst; |
||||
|
||||
if (segcount == 0) |
||||
snprintf(pathname, MAXPGPATH, "%s/%u", |
||||
dirpath, relnodeOid); |
||||
else |
||||
snprintf(pathname, MAXPGPATH, "%s/%u.%u", |
||||
dirpath, relnodeOid, segcount); |
||||
|
||||
if (stat(pathname, &fst) < 0) |
||||
{ |
||||
if (errno == ENOENT) |
||||
break; |
||||
else |
||||
ereport(ERROR, |
||||
(errcode_for_file_access(), |
||||
errmsg("could not stat \"%s\": %m", pathname))); |
||||
} |
||||
totalsize += fst.st_size; |
||||
} |
||||
|
||||
return totalsize; |
||||
} |
||||
|
||||
Datum |
||||
pg_relation_size_oid(PG_FUNCTION_ARGS) |
||||
{ |
||||
Oid relOid=PG_GETARG_OID(0); |
||||
HeapTuple tuple; |
||||
Form_pg_class pg_class; |
||||
Oid relnodeOid; |
||||
Oid tblspcOid; |
||||
|
||||
tuple = SearchSysCache(RELOID, |
||||
ObjectIdGetDatum(relOid), |
||||
0, 0, 0); |
||||
if (!HeapTupleIsValid(tuple)) |
||||
ereport(ERROR, |
||||
(ERRCODE_UNDEFINED_TABLE, |
||||
errmsg("relation with OID %u does not exist", relOid))); |
||||
|
||||
pg_class = (Form_pg_class) GETSTRUCT(tuple); |
||||
relnodeOid = pg_class->relfilenode; |
||||
tblspcOid = pg_class->reltablespace; |
||||
|
||||
ReleaseSysCache(tuple); |
||||
|
||||
PG_RETURN_INT64(calculate_relation_size(tblspcOid, relnodeOid)); |
||||
} |
||||
|
||||
Datum |
||||
pg_relation_size_name(PG_FUNCTION_ARGS) |
||||
{ |
||||
text *relname = PG_GETARG_TEXT_P(0); |
||||
RangeVar *relrv; |
||||
Relation relation; |
||||
Oid relnodeOid; |
||||
Oid tblspcOid; |
||||
|
||||
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
|
||||
relation = relation_openrv(relrv, AccessShareLock); |
||||
|
||||
tblspcOid = relation->rd_rel->reltablespace;
|
||||
relnodeOid = relation->rd_rel->relfilenode; |
||||
|
||||
relation_close(relation, AccessShareLock); |
||||
|
||||
PG_RETURN_INT64(calculate_relation_size(tblspcOid, relnodeOid)); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* Compute on-disk size of files for 'relation' according to the stat function,
|
||||
* optionally including heap data, index data, and/or toast data. |
||||
*/ |
||||
static int64 |
||||
calculate_complete_relation_size(Oid tblspcOid, Oid relnodeOid) |
||||
{ |
||||
Relation heapRelation; |
||||
Relation idxRelation; |
||||
Relation toastRelation; |
||||
Oid idxOid; |
||||
Oid idxTblspcOid; |
||||
Oid toastOid; |
||||
Oid toastTblspcOid; |
||||
bool hasIndices; |
||||
int64 size = 0; |
||||
List *indexoidlist; |
||||
ListCell *idx; |
||||
|
||||
heapRelation = relation_open(relnodeOid, AccessShareLock); |
||||
toastOid = heapRelation->rd_rel->reltoastrelid; |
||||
hasIndices = heapRelation->rd_rel->relhasindex; |
||||
|
||||
/* Get the heap size */ |
||||
size += calculate_relation_size(tblspcOid, relnodeOid); |
||||
|
||||
/* Get Index size */ |
||||
if ( hasIndices ) { |
||||
/* recursively include any dependent indexes ... */ |
||||
indexoidlist = RelationGetIndexList(heapRelation); |
||||
|
||||
foreach(idx, indexoidlist) { |
||||
idxOid = lfirst_oid(idx); |
||||
idxRelation = relation_open(idxOid, AccessShareLock); |
||||
idxTblspcOid = idxRelation->rd_rel->reltablespace; |
||||
size += calculate_relation_size(idxTblspcOid, idxOid); |
||||
relation_close(idxRelation, AccessShareLock); |
||||
} |
||||
list_free(indexoidlist); |
||||
} |
||||
|
||||
/* Close heapReleation now we no longer need it */ |
||||
relation_close(heapRelation, AccessShareLock); |
||||
|
||||
/* Get toast table size */ |
||||
if ( toastOid != 0 ) { |
||||
|
||||
/* recursively include any toast relations ... */ |
||||
toastRelation = relation_open(toastOid, AccessShareLock); |
||||
toastTblspcOid = toastRelation->rd_rel->reltablespace; |
||||
size += calculate_relation_size(toastTblspcOid, toastOid); |
||||
relation_close(toastRelation, AccessShareLock); |
||||
} |
||||
|
||||
return size; |
||||
} |
||||
|
||||
/*
|
||||
* Compute on-disk size of files for 'relation' including
|
||||
* heap data, index data, and toasted data. |
||||
*/ |
||||
Datum |
||||
pg_complete_relation_size_oid(PG_FUNCTION_ARGS) |
||||
{ |
||||
Oid relOid=PG_GETARG_OID(0); |
||||
HeapTuple tuple; |
||||
Form_pg_class pg_class; |
||||
Oid relnodeOid; |
||||
Oid tblspcOid; |
||||
|
||||
tuple = SearchSysCache(RELOID, |
||||
ObjectIdGetDatum(relOid), |
||||
0, 0, 0); |
||||
if (!HeapTupleIsValid(tuple)) |
||||
ereport(ERROR, |
||||
(ERRCODE_UNDEFINED_TABLE, |
||||
errmsg("relation with OID %u does not exist", relOid))); |
||||
|
||||
pg_class = (Form_pg_class) GETSTRUCT(tuple); |
||||
relnodeOid = pg_class->relfilenode; |
||||
tblspcOid = pg_class->reltablespace; |
||||
|
||||
ReleaseSysCache(tuple); |
||||
|
||||
PG_RETURN_INT64(calculate_complete_relation_size(tblspcOid, relnodeOid)); |
||||
} |
||||
|
||||
Datum |
||||
pg_complete_relation_size_name(PG_FUNCTION_ARGS) |
||||
{ |
||||
text *relname = PG_GETARG_TEXT_P(0); |
||||
RangeVar *relrv; |
||||
Relation relation; |
||||
Oid relnodeOid; |
||||
Oid tblspcOid; |
||||
|
||||
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
|
||||
relation = relation_openrv(relrv, AccessShareLock); |
||||
|
||||
tblspcOid = relation->rd_rel->reltablespace;
|
||||
relnodeOid = relation->rd_rel->relfilenode; |
||||
|
||||
relation_close(relation, AccessShareLock); |
||||
|
||||
PG_RETURN_INT64(calculate_complete_relation_size(tblspcOid, relnodeOid)); |
||||
} |
||||
|
||||
/*
|
||||
* formatting with size units |
||||
*/ |
||||
Datum |
||||
pg_size_pretty(PG_FUNCTION_ARGS) |
||||
{ |
||||
int64 size=PG_GETARG_INT64(0); |
||||
char *result=palloc(50+VARHDRSZ); |
||||
int64 limit = 10*1024; |
||||
int64 mult=1; |
||||
|
||||
if (size < limit*mult) |
||||
snprintf(VARDATA(result), 50, INT64_FORMAT" bytes", |
||||
size); |
||||
else |
||||
{ |
||||
mult *= 1024; |
||||
if (size < limit*mult) |
||||
snprintf(VARDATA(result), 50, INT64_FORMAT " kB", |
||||
(size+mult/2) / mult); |
||||
else |
||||
{ |
||||
mult *= 1024; |
||||
if (size < limit*mult) |
||||
snprintf(VARDATA(result), 50, INT64_FORMAT " MB", |
||||
(size+mult/2) / mult); |
||||
else |
||||
{ |
||||
mult *= 1024; |
||||
if (size < limit*mult) |
||||
snprintf(VARDATA(result), 50, INT64_FORMAT " GB", |
||||
(size+mult/2) / mult); |
||||
else |
||||
{ |
||||
mult *= 1024; |
||||
snprintf(VARDATA(result), 50, INT64_FORMAT " TB", |
||||
(size+mult/2) / mult); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
VARATT_SIZEP(result) = strlen(VARDATA(result)) + VARHDRSZ; |
||||
|
||||
PG_RETURN_TEXT_P(result); |
||||
} |
||||
Loading…
Reference in new issue