Как показать процент свободного места на диске по PostgreSQL? [Дубликат]

Еще один подход к возврату значения из асинхронной функции - передать объект, который сохранит результат от асинхронной функции.

Вот пример того же:

var async = require("async");

// This wires up result back to the caller
var result = {};
var asyncTasks = [];
asyncTasks.push(function(_callback){
    // some asynchronous operation
    $.ajax({
        url: '...',
        success: function(response) {
            result.response = response;
            _callback();
        }
    });
});

async.parallel(asyncTasks, function(){
    // result is available after performing asynchronous operation
    console.log(result)
    console.log('Done');
});

Я использую объект result для хранения значения во время асинхронной операции. Это позволяет получить результат даже после асинхронного задания.

Я использую этот подход много. Мне было бы интересно узнать, насколько хорошо этот подход работает, когда задействован результат обратно через последовательные модули.

6
задан Christian 22 April 2015 в 19:49
поделиться

3 ответа

В PostgreSQL в настоящее время нет функций для непосредственного отображения дискового пространства.

С одной стороны, какой диск? Производственный экземпляр PostgreSQL часто выглядит так:

  • /pg/pg94/: RAID6 с быстрым надежным хранением на RAID-контроллере BBU в режиме WB, для каталогов и наиболее важных данных
  • /pg/pg94/pg_xlog: быстрый надежный RAID1 для журналов транзакций
  • /pg/tablespace-lowredundancy: RAID10 быстрого дешевого хранилища для таких вещей, как индексы и таблицы UNLOGGED, которые вам не нужны, чтобы потерять вы можете использовать хранилище с более низким избыточным хранением
  • /pg/tablespace-bulkdata: RAID6 или аналогичный медленный магнитный носитель с близким расстоянием, используемый для старых журналов аудита, исторических данных, данных с записью в основном и других вещей, которые могут быть медленнее для доступа.
  • Журналы postgreSQL обычно находятся где-то в другом месте, но если это заполняется, система все равно может остановиться. Где зависит несколько настроек конфигурации, некоторые из которых вы вообще не видите из PostgreSQL, например параметры syslog.

Тогда есть факт, что «свободное» пространство необязательно означает, что PostgreSQL может использовать его (думаю: дисковые квоты, системно-зарезервированное дисковое пространство) и тот факт, что свободные блоки / байты не являются единственным ограничением, так как много файлов системы также имеют ограничения на количество файлов (inodes).

Как сообщает SELECT pg_get_free_disk_space() об этом?

Знание свободного места на диске может быть проблемой безопасности. Если это поддерживается, это то, что было бы доступно только для суперпользователя.

Что вы можете делать, это использовать ненадежный процедурный язык, например plpythonu, чтобы сделать операционную систему вызовы для опроса операционной системы хоста для информации о дисковой памяти, используя запросы против pg_catalog.pg_tablespace и использование параметра data_directory из pg_settings, чтобы обнаружить, где PostgreSQL хранит информацию в ОС хоста. Вы также должны проверить точки монтирования (unix / Mac) / точки соединения (Windows), чтобы узнать, находятся ли pg_xlog и т. Д. На отдельном хранилище. Это все равно не поможет вам с пространством для журналов.

Мне бы очень хотелось иметь SELECT * FROM pg_get_free_diskspace, который сообщил о главном пространстве datadir, и о любых точках подключения или точках соединения в нем, например для pg_xlog или pg_clog, а также сообщается каждое табличное пространство и любые точки монтирования внутри него. Это будет функция, возвращающая набор. Тем не менее, кто-то, кто заботится об этом, должен был бы попытаться реализовать его для всех целевых платформ , хотя сейчас и никто не хочет, чтобы это делало достаточно.


В среднем Если вы хотите упростить свои потребности:

  • Одна файловая система
  • Целевая ОС - совместимая с UNIX / POSIX, например Linux
  • Нет никакой системы квот
  • Нет процентного содержания в корневом зарезервированном блоке
  • Исходное значение inode не вызывает беспокойства

, тогда вы можете CREATE LANGUAGE plpython3u; и CREATE FUNCTION a LANGUAGE plpython3u, которая делает что-то вроде:

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

в функции, которая returns bigint и либо принимает datadir_path в качестве аргумента, либо обнаруживает ее, выполняя запрос SPI, например SELECT setting FROM pg_settings WHERE name = 'data_directory' из PL / Python.

Если вы хотите также поддерживать Windows, см. Кросс-платформенное пространство, оставшееся на томе, с помощью python . Я бы использовал запросы Windows Management Interface (WMI), а не использовать ctypes для вызова Windows API.

Или вы могли бы использовать эту функцию, которую кто-то написал в PL / Perlu , чтобы сделать он использует синтаксический вывод команды df и mount, который, вероятно, будет работать только в Linux, но, к сожалению, он написан заранее.

7
ответ дан Community 26 August 2018 в 00:14
поделиться

Вот реализация 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();
1
ответ дан craigds 26 August 2018 в 00:14
поделиться

C для тех, кто все еще хочет, чтобы инструмент проверял свободное пространство на сервере postgresql. Только для Linux и FreeBSD в настоящее время необходимо добавить соответствующие заголовки и определить для других ОС.

#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 26 August 2018 в 00:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: