Еще один подход к возврату значения из асинхронной функции - передать объект, который сохранит результат от асинхронной функции.
Вот пример того же:
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
для хранения значения во время асинхронной операции. Это позволяет получить результат даже после асинхронного задания.
Я использую этот подход много. Мне было бы интересно узнать, насколько хорошо этот подход работает, когда задействован результат обратно через последовательные модули.
В PostgreSQL в настоящее время нет функций для непосредственного отображения дискового пространства.
С одной стороны, какой диск? Производственный экземпляр PostgreSQL часто выглядит так:
/pg/pg94/
: RAID6 с быстрым надежным хранением на RAID-контроллере BBU в режиме WB, для каталогов и наиболее важных данных /pg/pg94/pg_xlog
: быстрый надежный RAID1 для журналов транзакций /pg/tablespace-lowredundancy
: RAID10 быстрого дешевого хранилища для таких вещей, как индексы и таблицы UNLOGGED
, которые вам не нужны, чтобы потерять вы можете использовать хранилище с более низким избыточным хранением /pg/tablespace-bulkdata
: RAID6 или аналогичный медленный магнитный носитель с близким расстоянием, используемый для старых журналов аудита, исторических данных, данных с записью в основном и других вещей, которые могут быть медленнее для доступа. Тогда есть факт, что «свободное» пространство необязательно означает, что 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
, а также сообщается каждое табличное пространство и любые точки монтирования внутри него. Это будет функция, возвращающая набор. Тем не менее, кто-то, кто заботится об этом, должен был бы попытаться реализовать его для всех целевых платформ , хотя сейчас и никто не хочет, чтобы это делало достаточно.
В среднем Если вы хотите упростить свои потребности:
, тогда вы можете 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, но, к сожалению, он написан заранее.
Вот реализация 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();
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);
}