Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 05e0bcb

Browse files
author
Commitfest Bot
committed
[CF 5651] v4 - Available disk space per tablespace
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/5651 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/Z9Vt6QYesJry7209@msg.df7cb.de Author(s): Christoph Berg
2 parents 29f7ce6 + a93a8e8 commit 05e0bcb

File tree

7 files changed

+171
-4
lines changed

7 files changed

+171
-4
lines changed

doc/src/sgml/func.sgml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30003,6 +30003,27 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
3000330003
</para></entry>
3000430004
</row>
3000530005

30006+
<row>
30007+
<entry role="func_table_entry"><para role="func_signature">
30008+
<indexterm>
30009+
<primary>pg_tablespace_avail</primary>
30010+
</indexterm>
30011+
<function>pg_tablespace_avail</function> ( <type>name</type> )
30012+
<returnvalue>bigint</returnvalue>
30013+
</para>
30014+
<para role="func_signature">
30015+
<function>pg_tablespace_avail</function> ( <type>oid</type> )
30016+
<returnvalue>bigint</returnvalue>
30017+
</para>
30018+
<para>
30019+
Returns the available disk space in the tablespace with the
30020+
specified name or OID. To use this function, you must
30021+
have <literal>CREATE</literal> privilege on the specified tablespace
30022+
or have privileges of the <literal>pg_read_all_stats</literal> role,
30023+
unless it is the default tablespace for the current database.
30024+
</para></entry>
30025+
</row>
30026+
3000630027
<row>
3000730028
<entry role="func_table_entry"><para role="func_signature">
3000830029
<indexterm>

doc/src/sgml/ref/psql-ref.sgml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1492,7 +1492,7 @@ SELECT $1 \parse stmt1
14921492
If <literal>x</literal> is appended to the command name, the results
14931493
are displayed in expanded mode.
14941494
If <literal>+</literal> is appended to the command name, each tablespace
1495-
is listed with its associated options, on-disk size, permissions and
1495+
is listed with its associated options, on-disk size and free disk space, permissions and
14961496
description.
14971497
</para>
14981498
</listitem>

src/backend/utils/adt/dbsize.c

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212
#include "postgres.h"
1313

1414
#include <sys/stat.h>
15+
#ifdef WIN32
16+
#include <fileapi.h>
17+
#include <errhandlingapi.h>
18+
#else
19+
#include <sys/statvfs.h>
20+
#endif
1521

1622
#include "access/htup_details.h"
1723
#include "access/relation.h"
@@ -316,6 +322,102 @@ pg_tablespace_size_name(PG_FUNCTION_ARGS)
316322
}
317323

318324

325+
/*
326+
* Return available disk space of tablespace. Returns -1 if the tablespace
327+
* directory cannot be found.
328+
*/
329+
static int64
330+
calculate_tablespace_avail(Oid tblspcOid)
331+
{
332+
char tblspcPath[MAXPGPATH];
333+
AclResult aclresult;
334+
#ifdef WIN32
335+
ULARGE_INTEGER lpFreeBytesAvailable;
336+
#else
337+
struct statvfs fst;
338+
#endif
339+
340+
/*
341+
* User must have privileges of pg_read_all_stats or have CREATE privilege
342+
* for target tablespace, either explicitly granted or implicitly because
343+
* it is default for current database.
344+
*/
345+
if (tblspcOid != MyDatabaseTableSpace &&
346+
!has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS))
347+
{
348+
aclresult = object_aclcheck(TableSpaceRelationId, tblspcOid, GetUserId(), ACL_CREATE);
349+
if (aclresult != ACLCHECK_OK)
350+
aclcheck_error(aclresult, OBJECT_TABLESPACE,
351+
get_tablespace_name(tblspcOid));
352+
}
353+
354+
if (tblspcOid == DEFAULTTABLESPACE_OID)
355+
snprintf(tblspcPath, MAXPGPATH, "base");
356+
else if (tblspcOid == GLOBALTABLESPACE_OID)
357+
snprintf(tblspcPath, MAXPGPATH, "global");
358+
else
359+
snprintf(tblspcPath, MAXPGPATH, "%s/%u/%s", PG_TBLSPC_DIR, tblspcOid,
360+
TABLESPACE_VERSION_DIRECTORY);
361+
362+
#ifdef WIN32
363+
if (! GetDiskFreeSpaceEx(tblspcPath, &lpFreeBytesAvailable, NULL, NULL))
364+
elog(ERROR, "GetDiskFreeSpaceEx failed: error code %lu", GetLastError());
365+
366+
return lpFreeBytesAvailable.QuadPart; /* ULONGLONG part of ULARGE_INTEGER */
367+
#else
368+
if (statvfs(tblspcPath, &fst) < 0)
369+
{
370+
if (errno == ENOENT)
371+
return -1;
372+
else
373+
ereport(ERROR,
374+
(errcode_for_file_access(),
375+
errmsg("could not statvfs directory \"%s\": %m", tblspcPath)));
376+
}
377+
378+
return fst.f_bavail * fst.f_frsize; /* available blocks times fragment size */
379+
#endif
380+
}
381+
382+
Datum
383+
pg_tablespace_avail_oid(PG_FUNCTION_ARGS)
384+
{
385+
Oid tblspcOid = PG_GETARG_OID(0);
386+
int64 avail;
387+
388+
/*
389+
* Not needed for correctness, but avoid non-user-facing error message
390+
* later if the tablespace doesn't exist.
391+
*/
392+
if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tblspcOid)))
393+
ereport(ERROR,
394+
errcode(ERRCODE_UNDEFINED_OBJECT),
395+
errmsg("tablespace with OID %u does not exist", tblspcOid));
396+
397+
avail = calculate_tablespace_avail(tblspcOid);
398+
399+
if (avail < 0)
400+
PG_RETURN_NULL();
401+
402+
PG_RETURN_INT64(avail);
403+
}
404+
405+
Datum
406+
pg_tablespace_avail_name(PG_FUNCTION_ARGS)
407+
{
408+
Name tblspcName = PG_GETARG_NAME(0);
409+
Oid tblspcOid = get_tablespace_oid(NameStr(*tblspcName), false);
410+
int64 avail;
411+
412+
avail = calculate_tablespace_avail(tblspcOid);
413+
414+
if (avail < 0)
415+
PG_RETURN_NULL();
416+
417+
PG_RETURN_INT64(avail);
418+
}
419+
420+
319421
/*
320422
* calculate size of (one fork of) a relation
321423
*

src/bin/psql/describe.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,15 @@ describeTablespaces(const char *pattern, bool verbose)
241241
printACLColumn(&buf, "spcacl");
242242
appendPQExpBuffer(&buf,
243243
",\n spcoptions AS \"%s\""
244-
",\n pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_size(oid)) AS \"%s\""
245-
",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
244+
",\n pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_size(oid)) AS \"%s\"",
246245
gettext_noop("Options"),
247-
gettext_noop("Size"),
246+
gettext_noop("Size"));
247+
if (pset.sversion >= 180000)
248+
appendPQExpBuffer(&buf,
249+
",\n pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_avail(oid)) AS \"%s\"",
250+
gettext_noop("Free"));
251+
appendPQExpBuffer(&buf,
252+
",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
248253
gettext_noop("Description"));
249254
}
250255

src/include/catalog/pg_proc.dat

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7733,6 +7733,14 @@
77337733
descr => 'total disk space usage for the specified tablespace',
77347734
proname => 'pg_tablespace_size', provolatile => 'v', prorettype => 'int8',
77357735
proargtypes => 'name', prosrc => 'pg_tablespace_size_name' },
7736+
{ oid => '6015',
7737+
descr => 'disk stats for the specified tablespace',
7738+
proname => 'pg_tablespace_avail', provolatile => 'v', prorettype => 'int8',
7739+
proargtypes => 'oid', prosrc => 'pg_tablespace_avail_oid' },
7740+
{ oid => '6016',
7741+
descr => 'disk stats for the specified tablespace',
7742+
proname => 'pg_tablespace_avail', provolatile => 'v', prorettype => 'int8',
7743+
proargtypes => 'name', prosrc => 'pg_tablespace_avail_name' },
77367744
{ oid => '2324', descr => 'total disk space usage for the specified database',
77377745
proname => 'pg_database_size', provolatile => 'v', prorettype => 'int8',
77387746
proargtypes => 'oid', prosrc => 'pg_database_size_oid' },

src/test/regress/expected/tablespace.out

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,27 @@ SELECT spcoptions FROM pg_tablespace WHERE spcname = 'regress_tblspacewith';
2020
{random_page_cost=3.0}
2121
(1 row)
2222

23+
-- check size functions
24+
SELECT pg_tablespace_size('pg_default') BETWEEN 1_000_000 and 10_000_000_000, -- rough sanity check
25+
pg_tablespace_size('pg_global') BETWEEN 100_000 and 10_000_000,
26+
pg_tablespace_size('regress_tblspacewith'); -- empty
27+
?column? | ?column? | pg_tablespace_size
28+
----------+----------+--------------------
29+
t | t | 0
30+
(1 row)
31+
32+
SELECT pg_tablespace_size('missing');
33+
ERROR: tablespace "missing" does not exist
34+
SELECT pg_tablespace_avail('pg_default') > 1_000_000,
35+
pg_tablespace_avail('pg_global') > 1_000_000,
36+
pg_tablespace_avail('regress_tblspacewith') > 1_000_000;
37+
?column? | ?column? | ?column?
38+
----------+----------+----------
39+
t | t | t
40+
(1 row)
41+
42+
SELECT pg_tablespace_avail('missing');
43+
ERROR: tablespace "missing" does not exist
2344
-- drop the tablespace so we can re-use the location
2445
DROP TABLESPACE regress_tblspacewith;
2546
-- This returns a relative path as of an effect of allow_in_place_tablespaces,

src/test/regress/sql/tablespace.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ CREATE TABLESPACE regress_tblspacewith LOCATION '' WITH (random_page_cost = 3.0)
1717
-- check to see the parameter was used
1818
SELECT spcoptions FROM pg_tablespace WHERE spcname = 'regress_tblspacewith';
1919

20+
-- check size functions
21+
SELECT pg_tablespace_size('pg_default') BETWEEN 1_000_000 and 10_000_000_000, -- rough sanity check
22+
pg_tablespace_size('pg_global') BETWEEN 100_000 and 10_000_000,
23+
pg_tablespace_size('regress_tblspacewith'); -- empty
24+
SELECT pg_tablespace_size('missing');
25+
SELECT pg_tablespace_avail('pg_default') > 1_000_000,
26+
pg_tablespace_avail('pg_global') > 1_000_000,
27+
pg_tablespace_avail('regress_tblspacewith') > 1_000_000;
28+
SELECT pg_tablespace_avail('missing');
29+
2030
-- drop the tablespace so we can re-use the location
2131
DROP TABLESPACE regress_tblspacewith;
2232

0 commit comments

Comments
 (0)