web-dev-qa-db-ja.com

Postgresで現在の空きディスク容量を取得するにはどうすればよいですか?

データベースで作業を開始する前に、少なくとも1Gbの空きディスク容量があることを確認する必要があります。私はこのようなものを探しています:

select pg_get_free_disk_space();

出来ますか? (私はそれについてドキュメントで何も見つけませんでした)。

PG:9.3&OS:Linux/Windows

11
Christian

PostgreSQLには現在、ディスク領域を直接公開する機能がありません。

一つには、どのディスク?実稼働PostgreSQLインスタンスは、多くの場合、次のようになります。

  • _/pg/pg94/_:カタログおよび最も重要なデータ用のWBモードのBBURAIDコントローラー上の高速で信頼性の高いストレージのRAID6
  • _/pg/pg94/pg_xlog_:トランザクションログ用の高速で信頼性の高いRAID1
  • _/pg/tablespace-lowredundancy_:インデックスやUNLOGGEDテーブルなど、冗長性​​の低いストレージを使用できるように失うことを気にしない、高速で安価なストレージのRAID10
  • _/pg/tablespace-bulkdata_:古い監査ログ、履歴データ、主に書き込みデータ、およびアクセスが遅くなる可能性のあるその他のものに使用される、RAID6または同様の低速ニアライン磁気ストレージ。
  • PostgreSQLログは通常、別の場所にありますが、これがいっぱいになると、システムが停止する場合があります。いくつかの構成設定に依存しますが、syslogオプションのように、PostgreSQLからはまったく表示されないものもあります。

次に、「空き」スペースが必ずしもPostgreSQLがそれを使用できることを意味するわけではないという事実(ディスククォータ、システム予約ディスクスペースなど)、および空きスペースブロック/バイト]という事実があります。多くのファイルシステムにはファイル(iノード)の数にも制限があるため、だけが制約ではありません。

ASELECT pg_get_free_disk_space()はこれをどのように報告しますか?

空きディスク容量を知ることは、セキュリティ上の懸念事項になる可能性があります。サポートされている場合、少なくともスーパーユーザーにのみ公開されるものです。

canは、plpythonuのような信頼できない手続き型言語を使用して、オペレーティングシステムコールを実行し、_pg_catalog.pg_tablespace_に対するクエリを使用して、ホストOSにディスクスペース情報を問い合わせます。 _data_directory_から_pg_settings_を設定して、PostgreSQLがホストOS上のどこにデータを保持しているかを検出します。また、マウントポイント(unix/Mac)/ジャンクションポイント(Windows)をチェックして、_pg_xlog_などが別のストレージにあるかどうかを確認する必要があります。ただし、これでもログ用のスペースはあまり役に立ちません。

メインのdatadirスペースとその中のマウントポイントまたはジャンクションポイントを報告する_SELECT * FROM pg_get_free_diskspace_が欲しいのですが、_pg_xlog_または_pg_clog_のように、各テーブルスペースとその中のマウントポイント。セットを返す関数になります。十分に気にかけている人は、わざわざそれを実装する必要がありますすべてのターゲットプラットフォームに対してしかし、今のところ、誰もそれを十分に実行することを望んでいません。


それまでの間、ニーズを簡素化する場合は、次のことを行ってください。

  • 1つのファイルシステム
  • ターゲットOSはLinuxと同様にUNIX/POSIX互換です
  • クォータシステムが有効になっていません
  • ルート予約ブロックの割合はありません
  • iノードの枯渇は問題ではありません

次に、_CREATE LANGUAGE plpython3u;_および_CREATE FUNCTION_ _LANGUAGE plpython3u_関数を実行できます。

_import os
st = os.statvfs(datadir_path)
return st.f_bavail * st.f_frsize
_

_returns bigint_であり、引数として_datadir_path_を受け取るか、PL/Python内から_SELECT setting FROM pg_settings WHERE name = 'data_directory'_のようなSPIクエリを実行することにより、それを検出する関数内。

Windowsもサポートしたい場合は、 Pythonを使用してボリュームに残っているクロスプラットフォームスペース を参照してください。ただし、ctypesを使用してWindows APIを呼び出すのではなく、Windows Management Interface(WMI)クエリを使用します。

または、 誰かがPL/Perluで書いたこの関数を使用dfおよびmountコマンド出力解析を使用してそれを行うことができます。これはおそらくLinuxでのみ機能しますが、ちょっと、事前に作成されています。

13
Craig Ringer

これは、拡張言語なしでディスクの空き容量を増やす簡単な方法です。pgsqlを使用して関数を定義するだけです。

CREATE OR REPLACE FUNCTION sys_df() RETURNS SETOF text[]
LANGUAGE plpgsql $$
BEGIN
    CREATE TEMP TABLE IF NOT EXISTS tmp_sys_df (content text) ON COMMIT DROP;
    COPY tmp_sys_df FROM PROGRAM 'df | tail -n +2';
    RETURN QUERY SELECT regexp_split_to_array(content, '\s+') FROM tmp_sys_df;
END;
$$;

使用法:

select * from sys_df();
                          sys_df                               
-------------------------------------------------------------------
 {overlay,15148428,6660248,7695656,46%,/}
 {overlay,15148428,6660248,7695656,46%,/}
 {tmpfs,65536,0,65536,0%,/dev}
 {tmpfs,768284,0,768284,0%,/sys/fs/cgroup}
 {/dev/sda2,15148428,6660248,7695656,46%,/etc/resolv.conf}
 {/dev/sda2,15148428,6660248,7695656,46%,/etc/hostname}
 {/dev/sda2,15148428,6660248,7695656,46%,/etc/hosts}
 {shm,65536,8,65528,0%,/dev/shm}
 {/dev/sda2,15148428,6660248,7695656,46%,/var/lib/postgresql/data}
 {tmpfs,65536,0,65536,0%,/proc/kcore}
 {tmpfs,65536,0,65536,0%,/proc/timer_list}
 {tmpfs,65536,0,65536,0%,/proc/sched_debug}
 {tmpfs,768284,0,768284,0%,/sys/firmware}
(13 rows)

ディスク上の同じパスにすべてのデータを保存するときに、df $PGDATA | tail -n +2の代わりにdf | tail -n +2を使用します。この場合、関数は$ PGDATAパスに対して1行のディスク使用量のみを返します。

セキュリティに関する注意

[〜#〜]プログラム[〜#〜]は、両刃の剣のように、シェルで任意のコマンドを実行できます。固定のコマンド文字列を使用するか、少なくともユーザー入力を渡さないようにすることをお勧めします。 ドキュメントの詳細を参照

3
eshizhan

これは、私たちがしばらく使用してきたplpython2uの実装です。

-- NOTE this function is a security definer, so it carries the superuser permissions
-- even when called by the plebs.
-- (required so we can access the data_directory setting.)
CREATE OR REPLACE FUNCTION get_tablespace_disk_usage()
    RETURNS TABLE (
        path VARCHAR,
        bytes_free BIGINT,
        total_bytes BIGINT
    )
AS $$
import os

data_directory = plpy.execute("select setting from pg_settings where name='data_directory';")[0]['setting']
records = []

for t in plpy.execute("select spcname, spcacl, pg_tablespace_location(oid) as path from pg_tablespace"):
    if t['spcacl']:
        # TODO handle ACLs. For now only show public tablespaces.
        continue

    name = t['spcname']
    if name == 'pg_default':
        path = os.path.join(data_directory, 'default')
    Elif name == 'pg_global':
        path = os.path.join(data_directory, 'global')
    else:
        path = t['path']

    # not all tablespaces actually seem to exist(?) in particular, pg_default.
    if os.path.exists(path):
        s = os.statvfs(path)
        total_bytes = s.f_blocks * s.f_frsize
        bytes_free = s.f_bavail * s.f_frsize

        records.append((path, bytes_free, total_bytes))

return records

$$ LANGUAGE plpython2u STABLE SECURITY DEFINER;

使用法は次のようなものです。

SELECT path, bytes_free, total_bytes FROM get_tablespace_disk_usage();
2
craigds

Cバージョンはまだpostgresqlサーバーの空き領域をチェックするツールが必要な人向けです。現在、LinuxとFreeBSDの場合のみ、他のOS用に適切なヘッダーと定義を追加する必要があります。

#if defined __FreeBSD__
# include <sys/param.h>
# include <sys/mount.h>
#Elif defined __linux__
# define _XOPEN_SOURCE
# define _BSD_SOURCE
# include <sys/vfs.h>
#else
# error Unsupported OS
#endif
#include <postgres.h>
#include <catalog/pg_type.h>
#include <funcapi.h>
#include <utils/builtins.h>

/* Registration:
CREATE FUNCTION disk_free(path TEXT) RETURNS TABLE (
  size BIGINT, free BIGINT, available BIGINT, inodes INTEGER, ifree INTEGER, blksize INTEGER
) AS '$pglib/pg_df.so', 'df' LANGUAGE c STRICT;
*/

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

PG_FUNCTION_INFO_V1(df);

Datum df(PG_FUNCTION_ARGS)
{
  TupleDesc tupdesc;
  AttInMetadata *attinmeta;
  HeapTuple Tuple;
  Datum result;
  char **values;
  struct statfs sfs;
  const char* path = text_to_cstring(PG_GETARG_TEXT_P(0));

  if(get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
    ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context that cannot accept type record")));
  attinmeta = TupleDescGetAttInMetadata(tupdesc);

  if(0 != statfs(path, &sfs))
    ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("statfs() system call failed: %m")));

  values = (char **) palloc(6 * sizeof(char *));
  values[0] = (char *) palloc(20 * sizeof(char));
  values[1] = (char *) palloc(20 * sizeof(char));
  values[2] = (char *) palloc(20 * sizeof(char));
  values[3] = (char *) palloc(10 * sizeof(char));
  values[4] = (char *) palloc(10 * sizeof(char));
  values[5] = (char *) palloc(10 * sizeof(char));

  int64 df_total_bytes = sfs.f_blocks * sfs.f_bsize;
  int64 df_free_bytes  = sfs.f_bfree  * sfs.f_bsize;
  int64 df_avail_bytes = sfs.f_bavail * sfs.f_bsize;
  snprintf(values[0], 20, "%lld", df_total_bytes);
  snprintf(values[1], 20, "%lld", df_free_bytes);
  snprintf(values[2], 20, "%lld", df_avail_bytes);
  snprintf(values[3], 10, "%d", sfs.f_files);
  snprintf(values[4], 10, "%d", sfs.f_ffree);
  snprintf(values[5], 10, "%d", sfs.f_bsize);

  Tuple = BuildTupleFromCStrings(attinmeta, values);
  return HeapTupleGetDatum(Tuple);
}
0
Vasily Redkin