Безопасный и эффективный способ изменить несколько файлов в системах POSIX?

const div = document.querySelector('div');
const btn = document.querySelector('#timerBtn');
const resetbtn = document.querySelector('#reset');

let startFlag = 0;
let count = 0;
let intervalId;
const ms = 1000;

div.textContent = count;

btn.addEventListener('click', function() {
    startFlag = startFlag + 1;

    if(startFlag%2 !== 0) { // Start button clicked;
        btn.textContent = 'Stop';
        startTimer();
    } else {
        btn.textContent = 'Start';
        stopTimer();
    }
});

resetbtn.addEventListener('click', function() {
    count = 0;
    div.textContent = count;
});

function startTimer() {
    intervalId = setInterval(() => {
        count = count + 1;
        div.textContent = count;
    }, 1000);
}

function stopTimer() {
    clearInterval(intervalId);
}
<div></div>
<button id="timerBtn">Start</button>
<button id="reset">Reset</button>

7
задан Raynet 20 March 2009 в 12:33
поделиться

3 ответа

Короткий ответ: Решение этого в слое приложения является неправильным местом. EXT4 должен удостовериться, что после того, как я закрываю файл, данные записаны своевременно. Поскольку это теперь, EXT4 "оптимизирует" эту запись, чтобы смочь собрать больше запросов записи и разорвать их сразу.

Проблема очевидна: Независимо от того, что Вы делаете, Вы не можете быть уверены, что Ваши данные заканчиваются на диске. Вызов fdisk () вручную только делает вещи хуже: Вы в основном мешаете оптимизации EXT4, замедляя целую систему.

OTOH, EXT4 имеет всю информацию, необходимую для высказывания образованного предположения, когда необходимо выписать данные к диску. В этом случае я переименовываю временный файл к названию существующего файла. Для EXT4 это означает, что он должен или отложить переименовывание (таким образом, данные исходного файла остаются неповрежденными после катастрофического отказа), или он должен сбросить сразу. Так как это не может отложить переименовывание (следующий процесс мог бы хотеть видеть новые данные), переименовывание неявно означает сбрасывать, и тот сброс должен произойти на уровне FS, не слое приложения.

EXT4 мог бы создать виртуальную копию файловой системы, которая содержит изменения, в то время как диск (еще) не изменяется. Но это не влияет на конечную цель: приложение не может знать, какая оптимизация FS при попытке делать и поэтому, FS должен удостовериться, что это делает свое задание.

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

Пока Tso полагает, что более важно иметь быстрый FS, а не тот, который ведет себя правильно, я предлагаю не обновить до EXT4 и закрыться, все отчеты об ошибках об этом "работы, как разработано Tso".

[РЕДАКТИРОВАНИЕ] еще Некоторые мысли об этом. Вы могли использовать базу данных вместо файла. Давайте проигнорируем отходы ресурса на мгновение. Кто-либо может гарантировать, что файлы, которые использует база данных, не станут поврежденными катастрофическим отказом? Вероятно. База данных может записать данные и назвать fsync () каждую минуту или около этого. Но затем, Вы могли сделать то же:

while True; do sync ; sleep 60 ; done

Снова, ошибка в FS препятствует тому, чтобы это работало в каждом случае. Иначе люди не были бы так побеспокоены этой ошибкой.

Вы могли использовать второстепенного демона конфигурации как реестр Windows. Демон записал бы все конфигурации в одном большом файле. Это могло назвать fsync () после выписывания всего. Проблема, решенная... для Ваших конфигураций. Теперь необходимо сделать то же для всего остального запись приложений: Текстовые документы, изображения, безотносительно. Я подразумеваю, что почти любой процесс Unix создает файл. Это - долбаное основание целой идеи Unix!

Очевидно, это не жизнеспособный путь. Таким образом, ответ остается: на Вашей стороне нет никакого решения. Продолжайте беспокоить Tso и других разработчиков FS, пока они не исправят свои ошибки.

3
ответ дан 7 December 2019 в 14:38
поделиться

Необходимо подкачать 3 и 4 в последнем списке - fsync(fd) использует дескриптор файла. и я не вижу, почему это было бы особенно дорогостоящим - Вы хотите данные, записанные в диск завершением () так или иначе. Таким образом, стоимость будет тем же между тем, что Вы хотите произойти и что произойдет с fsync().

Если стоимость слишком много, (и у Вас есть она), fdatasync(2) постарайтесь не синхронизировать метаданные, так должен легче стоиться.

Править: Таким образом, я записал некоторым чрезвычайно hacky тестовый код:

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>
#include <stdio.h>
#include <string.h>

static void testBasic()
{
    int fd;
    const char* text = "This is some text";

    fd = open("temp.tmp", O_WRONLY | O_CREAT);
    write(fd,text,strlen(text));
    close(fd);
    rename("temp.tmp","temp");
}

static void testFsync()
{
    int fd;
    const char* text = "This is some text";

    fd = open("temp1", O_WRONLY | O_CREAT);
    write(fd,text,strlen(text));
    fsync(fd);
    close(fd);
    rename("temp.tmp","temp");
}

static void testFdatasync()
{
    int fd;
    const char* text = "This is some text";

    fd = open("temp1", O_WRONLY | O_CREAT);
    write(fd,text,strlen(text));
    fdatasync(fd);
    close(fd);
    rename("temp.tmp","temp");
}

#define ITERATIONS 10000

static void testLoop(int type)
{
    struct timeval before;
    struct timeval after;
    long seconds;
    long usec;
    int i;

    gettimeofday(&before,NULL);
    if (type == 1)
    {
        for (i = 0; i < ITERATIONS; i++)
        {
            testBasic();
        }
    }
    if (type == 2)
    {
        for (i = 0; i < ITERATIONS; i++)
        {
            testFsync();
        }
    }
    if (type == 3)
    {
        for (i = 0; i < ITERATIONS; i++)
        {
            testFdatasync();
        }
    }
    gettimeofday(&after,NULL);

    seconds = (long)(after.tv_sec - before.tv_sec);
    usec = (long)(after.tv_usec - before.tv_usec);
    if (usec < 0)
    {
        seconds--;
        usec += 1000000;
    }

    printf("%ld.%06ld\n",seconds,usec);
}

int main()
{
    testLoop(1);
    testLoop(2);
    testLoop(3);
    return 0;
}

На моем ноутбуке, который производит:

0.595782
6.338329
6.116894

Который предлагает делать fsync() является в ~10 раз более дорогим. и fdatasync() является немного более дешевым.

Я предполагаю проблему, которую я вижу, то, что каждое приложение собирается думать, что это - данные, достаточно важно для fsync (), таким образом, преимущества производительности слияния переписывают минуту, будет устранен.

0
ответ дан 7 December 2019 в 14:38
поделиться

Мой собственный ответ должен был бы придерживаться модификаций на временных файлах, и после окончания записи их всех, сделать один fsync () и затем переименовывает на них всех.

1
ответ дан 7 December 2019 в 14:38
поделиться
Другие вопросы по тегам:

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