Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2005.06.29;
Скачать: [xml.tar.bz2];

Вниз

TerminateProcess   Найти похожие ветки 

 
Суслик ©   (2005-04-25 14:53) [0]

Добрый день.

Есть такой псевдокод:

... запись в файл 200 мб из памяти
sleep(500);
TerminateProcess(GetCurrentProcess);


Вопрос: почему система ждет, когда файл запишется и только потом приложение закрывается? Вернее, почему файл оказывается записанным?

ЗЫ. win2000 server, диски ntfs и fat32.


 
Digitman ©   (2005-04-25 14:55) [1]


> почему файл оказывается записанным?


а почему он не должен быть записанным в дан.случае ?


 
Суслик ©   (2005-04-25 15:14) [2]


>  [1] Digitman ©   (25.04.05 14:55)

ну вроде процесс должен прекратиться.

Кто файл дописывает? Ядро? Какой тут механизм?

Файл - объект ядра. Логично предположить, что процесс дав команду ядру записать в файл данные, уже не может повлиять на процесс записи - ядро данные запишет. Но запись то идет из памяти, а память принадлежит процессу, т.е. если процесс во время записи в файл "умрет", то и умрет его память. Откуда ядро берет данные для записи?


 
alpet ©   (2005-04-25 15:19) [3]

Все бы хорошо, да только стандартные функции записи в файл являются синхронными, и после вызова их можно быть уверенным что данные либо в файле, либо в системном кэше.


 
mgcr ©   (2005-04-25 15:21) [4]


> Какой тут механизм?


CloseHandle


> Но запись то идет из памяти, а память принадлежит процессу,
> т.е. если процесс во время записи в файл "умрет", то и умрет
> его память. Откуда ядро берет данные для записи?


Из кэша.

Память не принадлежит процессу. Память принадлежит диспетчеру памяти и только.


 
Суслик ©   (2005-04-25 15:28) [5]


>  [3] alpet ©   (25.04.05 15:19)

эттта, виноват, неверный пример написал (упростил сильно) - запись в файл у меня идет в дополнительном потоке, а прерывается процесс в главном потоке. Т.е. про синхронность здесь говорить не приходится.


>  [4] mgcr ©   (25.04.05 15:21)

Игорь, я знаю, что при TermProcess происход CloseHandle для всех объектов, в том числе и для файлов - это явно описано в MSDN. Но я не понимаю, если я (процесс) закрыл handle у файла, почему меня (процесс) кто-то "держит". Т.е. такое ощущение (используя секундомер) меня держар ровно пока файл не запишет все данные из моей памяти. Вот я и спрашиваю - какой тут механизм. Может быть такое, что файл ссылается на процесс, и пока не допишется до конца не делает процессу Closehandle тем самым удерживая процесс в памяти?


 
mgcr ©   (2005-04-25 15:46) [6]

Суслик ©   (25.04.05 15:28) [5]


> Но я не понимаю, если я (процесс) закрыл handle у файла,
> почему меня (процесс) кто-то "держит".


Пока Handle не закроется. А закрытие такого Handle требует сброса кэша. Пока он сбрасывается, Close тебя не отпускает.


 
Суслик ©   (2005-04-25 15:57) [7]


>  закрытие такого Handle требует сброса кэша. Пока он сбрасывается,
> Close тебя не отпускает.

тогда как это соотносится с?

If there is data in the internal buffer when the file is closed, the operating system does not automatically write the contents of the buffer to the disk before closing the file. If the application does not force the operating system to write the buffer to disk before closing the file, the caching algorithm determines when the buffer is written.

источник http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/file_management_functions.asp

Кто-все таки процесс держит?


 
alpet ©   (2005-04-25 16:04) [8]

Твой процесс держит система не до тех пор "пока запишется файл", а до тех пор пока не осуществится копирование заказанного блока  памяти в системный кэш. С учетом того что кэш (при ограниченном объеме оперативной памяти) не безразмерный, система вынуждена записывать его на диск. В этом случае файл частично будет записан и частично останется в кэше к моменту закрытия процесса.


 
Суслик ©   (2005-04-25 16:12) [9]


>  [8] alpet ©   (25.04.05 16:04)

очень полезная информация.
Разреши поинтересоваться где ты ее взял?


 
alpet ©   (2005-04-25 16:18) [10]

По словам Рихтера функция TerminateThread - ассинхронная. Так что надеятся на мгновенную смерть потока не стоит. В любом случае стоит почитать оригинал.

Можешь поэкспериментировать с более жестким завершением потока - уничтожением процесса являющимся отладчиком по отношению к исходниму процессу.

В моей практике были случаи когда время завершения потока
доходило до нескольких минут. Но это было следствием странного зависания потока.


 
mgcr ©   (2005-04-25 16:18) [11]


> the caching algorithm determines when the buffer is written.


Вот тебе все и сказали.


 
alpet ©   (2005-04-25 16:26) [12]

>  [8] alpet ©   (25.04.05 16:04)

очень полезная информация.
Разреши поинтересоваться где ты ее взял?


Я в давние времена изучал работу DOS утилиты smartdrv.exe, и насколько понимаю принципы кэширования с тех времен не сильно изменились. Что касается отработки в твоем случае, поток и в самом деле должен умереть практически сразу, засекай время ожидания WaitForSingleObject. Ведь Windows на самом деле нужно АП процесса, которое никуда не девается после завершении "не последнего" потока.


 
mgcr ©   (2005-04-25 16:28) [13]


> насколько понимаю принципы кэширования с тех времен не сильно
> изменились


Вообще-то сильно. Советую изучить Руссиновича с Соломоном.


 
alpet ©   (2005-04-25 16:33) [14]

2 mgcr

Особенно жду. Посылка скоро будет доставлена. Но основной принцип - отложенная запись. На что его можно изменить? Конечно кэширование стало более интеллектуальным, и размер системного кэша теперь изменяется системой realtime. Но как это на высокоуровневой доступ к файлам может повлиять ?


 
Суслик ©   (2005-04-25 16:55) [15]


> [11] mgcr ©   (25.04.05 16:18)

Как раз это противоречит твоим словам...
При close handle никто не сбрасывает кэш.


 
mgcr ©   (2005-04-25 17:04) [16]

alpet ©   (25.04.05 16:33) [14]


> Но основной принцип - отложенная запись. На что его можно
> изменить?


Основной принцип - диспетчер кеша не управляет записью. Более того, он даже не знает, какие данные из файлов присутствуют в памяти. Этим всем управляет диспетчер памяти.


 
alpet ©   (2005-04-25 17:07) [17]

Для принудительной выгрузки буферов надо вызывать FlushFileBuffers. Интересно если попываться завершить поток в момент выполнения функции - система уничтожит его до завершения записи системного кэша? Если в функции осуществляется обработка системного вызова - по идее не должно. Можно сравнить время ожидания WaitForSingleObject (hThread) с FlushFileBuffers и без оного.


 
alpet ©   (2005-04-25 17:11) [18]

mgcr ©   (25.04.05 17:04) [16]

Надо будет изучить вопрос. В любом случае выгрузка страниц физической памяти на диск должна выполнятся при ее не хватке.


 
mgcr ©   (2005-04-25 17:25) [19]


> If the application does not force the operating system to
> write the buffer to disk before closing the file


Дима, а ты уверен, что файл открывается с отложенной записью ? :)


 
Суслик ©   (2005-04-25 17:41) [20]


>  [19] mgcr ©   (25.04.05 17:25)


> If the application does not force the operating system to
>

Игорь, насколько я понимаю не форсить запись файла, является умолчательным поведением. Я не прав? Какой конкретно флаг приводит к отложенной записи?


 
mgcr ©   (2005-04-25 17:52) [21]

Суслик ©   (25.04.05 17:41) [20]

Ты бы код записи что ли привел. А то гадаем на кофейной гуще.


 
Суслик ©   (2005-04-25 18:13) [22]

Господа. Я был неправ. Дома у меня работает несколько иначе чем на работе.
Дома (2000 server) - при terminateProcess ждет пока весь файл не будет
записан
На работке (2000 prof) - при terminateProcess сразу выходит, но файл еще потом некоторове вермя недоступен, но в итоге записывается правильной информацией.

Мой код.
модуль

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type
 TForm1 = class(TForm)
   Button1: TButton;
   Memo1: TMemo;
   procedure Button1Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

const
  cLen = 100*1024*1024;
var
  fBuffer: packed array[0..cLen-1] of byte;

type
  TFileThread = class(TThread)
     protected procedure Execute(); override;
  end;

procedure TFileThread.Execute();
var
  kFS: TFileStream;
begin
  kFS := TFileStream.Create("d:\temp\data", fmCreate or fmShareExclusive);
  try
     kFS.WriteBuffer(fBuffer, cLen);
  finally
     kFS.Free();
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  kM: String;
begin
  // записываем первый файл
  FillChar(fBuffer, cLen, ord("0"));
  DateTimeToString(kM, "начало записи файла 1 = yyyy-mm-dd hh:nn:zzz", Now());
  Memo1.Lines.Add(kM);
  with TFileThread.Create(true) do
  begin
     Resume();
     WaitFor();
     Free();
  end;
  DateTimeToString(kM, "конец записи файла 1 = yyyy-mm-dd hh:nn:zzz", Now());
  Memo1.Lines.Add(kM);

  // перезаписываем файл
  FillChar(fBuffer, cLen, ord("1"));
  DateTimeToString(kM, "начало записи файла 2 = yyyy-mm-dd hh:nn:zzz", Now());
  Memo1.Lines.Add(kM);
  with TFileThread.Create(true) do
  begin
     Resume();
  end;

  Sleep(500);

  DateTimeToString(kM, "вызов GetCurrentProcess = yyyy-mm-dd hh:nn:zzz", Now());
  Memo1.Lines.Add(kM);

  TerminateProcess(GetCurrentProcess, 0);
end;

end.


dfm

object Form1: TForm1
 Left = 396
 Top = 106
 Width = 446
 Height = 403
 Caption = "write test"
 Color = clBtnFace
 Font.Charset = DEFAULT_CHARSET
 Font.Color = clWindowText
 Font.Height = -11
 Font.Name = "MS Sans Serif"
 Font.Style = []
 OldCreateOrder = False
 PixelsPerInch = 96
 TextHeight = 13
 object Button1: TButton
   Left = 8
   Top = 24
   Width = 75
   Height = 25
   Caption = "write"
   TabOrder = 0
   OnClick = Button1Click
 end
 object Memo1: TMemo
   Left = 104
   Top = 24
   Width = 329
   Height = 345
   TabOrder = 1
 end
end


 
Суслик ©   (2005-04-25 18:24) [23]

Хотел бы еще упомянуть про то, чего я добиваюсь.

С настоящий момент я провожу исследования в области как сохранить большой бинарных файл так, чтобы если в момент записи произойдет выключение питания, то файл либо останется в состоянии до записи, или будет иметь новое содержание.

Собственно вопрос с terminateProcess слабо относится к моей задаче. Я просто исходно по наивности думал, что таким образом смогу смоделировать сбой :))) не вышло :)))

Теперь вопрос про terminateProcess представляет скорее познавательный интерес.


 
alpet ©   (2005-04-25 18:30) [24]

>> TerminateProcess(GetCurrentProcess, 0);
Вот из-за этой строки все и может развиваться согласно [8]. Выполни вместо этого:

with TFileThread.Create(true) do
 begin
  Resume();
  Sleep (500);
  nStart := GetTickCount;
  TerminateThread (Handle);
 end;
WaitForSingleObject (handle, 5000);
nStart := GetTickCount - nStart;
ShowMessage (IntToStr (nStart) ); // show waiting delay

 
Тогда поток должен поидее завершиться сразу.


 
mgcr ©   (2005-04-25 18:31) [25]


> С настоящий момент я провожу исследования в области как
> сохранить большой бинарных файл так, чтобы если в момент
> записи произойдет выключение питания, то файл либо останется
> в состоянии до записи, или будет иметь новое содержание


UPS - рулез фарева. NTFS - рулез фарева. NTFS+UPS двойной рулез.

А зачем надо гонять такие мегабайты туда-сюда, кстати ?


 
alpet ©   (2005-04-25 18:33) [26]

С настоящий момент я провожу исследования в области как сохранить большой бинарных файл так, чтобы если в момент записи произойдет выключение питания, то файл либо останется в состоянии до записи, или будет иметь новое содержание.

Это проще промоделировать в реальности :=)  
Во всяком случае чтобы спровоцировать ошибку в твоем случае, надо попробывать принудительно высвободить страницы памяти из первого потока (VirtualFree), в тот момент когда второй будет пытаться их записывать.


 
mgcr ©   (2005-04-25 18:41) [27]


> Собственно вопрос с terminateProcess слабо относится к моей
> задаче. Я просто исходно по наивности думал, что таким образом
> смогу смоделировать сбой :))) не вышло :)))


Кнопка Reset.

Но опять же, извини, не вижу смысла в страдании подобной ерундой. Если ты обмениваешься большими объемами, то средствами файловой системы я полагаю, ты не добьешься поведения "либо полностью старое состояние файла, либо полностью новое". То есть, файловые системы, они, некоторые, транзакционные, но ихние транзакции к пользовательским данным не имеют никакого отношения.

Если очень хочется помучиться, то заведи два файла (небольших, по байту или меньше), перед началом записи большого объема запиши первый файл, означающий "запись данных начата" (и закрой его, сбросив буфер), по успешному окончании записи объема запиши второй файл, означающий "запись данных завершена", а первый удали. Тогда при старте ты будешь знать, в каком состоянии находятся данные твоего большого объема.
Но лучше СУБД использовать - там этот механизм уже успешно реализован.


 
Суслик ©   (2005-04-25 18:47) [28]


> [25] mgcr ©   (25.04.05 18:31)


> А зачем надо гонять такие мегабайты туда-сюда, кстати ?

надо, чтобы программа работала и хранила без всяких сторонних разработок, типа серверов и пр - только файлы. Структура данных чрезвычайно проста - большой бинарный поток. На самом деле он намного меньше - порядка 1-2 мб, просто используя 100мб - легче поймать момент, когда запись не завершена.

Я смотрел fireBird. Мне не равится там ситуация с его поддержкой, и в частности с документированностью. Да и вообще - из пушки по ...

Задача просто - раз в минуту сохранять макс. до 3 мб памяти в один файл. Нужно сделать так, чтогбы ничего не потерялось, т.е. при следующей загрузке:
1. Либо оказался корректный новый файл, при этом информация о сбое отсутстует.
2. Либо оказался корректный старый файл, при этом присутствует информация о сбое.
1


 
Суслик ©   (2005-04-25 18:51) [29]


> [27] mgcr ©   (25.04.05 18:41)


> Если очень хочется помучиться, то заведи два файла (небольших,
> по байту или меньше), перед


Хочу мучаться ерундой, не осуждай уж. Серьезно.

Чем такой вариант хуже?

1. При записи файл данных "a.dat" переименовывается в "a.old"
2. В файл "a.dat" ведется запись новых данных.
3. Происходит сброс данных в файл "a.dat".
4. Файл "a.old" удаляется.

При старте я будут знать дописался ли файл или нет. Если есть old, значит не дописался. Если нет, то значит все ок (т.е. я даже не знаю, про то, что что-то случилось)


 
alpet ©   (2005-04-25 19:17) [30]

Самая лучшая защита - CRC. В твоем случае не обязательно хэшировать весь файл, но вполне возможно хэшировать его окончание. Если идти твоим путем - можно вести лог-файл в который будут записываться имена файлов успешно записанных на диск, причем запись имен вести через некоторое время (5-10 сек после выполнения FlushFileBuffersEx) что бы была хоть какая-то гарантия, что и аппаратные буфера жесткого диска записались.


 
Alex Konshin ©   (2005-04-26 09:47) [31]

Ты все 3M перезаписываешь каждый раз?
Почему нельзя писать в другой файл?
Подозреваю, что ты хочешь иметь некую маленькую базу данных.
Могу предложить организовать внутри этого своего файла страничную организацию и изменения всегда писать в другую страницу кроме корневой страницы (твой FAT), которая должна записываться последней. Если размер страницы в файле будет равен размеру сектора (т.е. 512), то как раз и будет гарантироваться транзакциональность изменения. Т.к. 512 байт не достаточно для FAT файла размером 3M, то придется делать его двухуровневым. Т.е. выглядеть должно так:
0-й гиперблок содержит номера блоков, где сидят соответствующие гиперблоки.
Гиперблоки содержат уже номера блоков самого логического файла.

Запись изменений всегда должна происходить в порядке снизу вверх. Т.е. сначала записываешь измененный или новый сектор файла, причем этот сектор обязательно должен быть из списка свободных, ни в коем случае нельзя заменять блок на месте. Потом изменяешь соответствующий гиперблок (пишешь в него номер нового сектора данных) и опять-таки пишешь его на новое место. И, наконец, пишешь корневой гипреблок, в котором изменен номер только что записанного гиперблока, вот его уже пишешь по месту. Весь твой файл нужно открывать без кеширования или, еще лучше, организовать memory mapping.

Собственно, я упрощенно описал принцип работы транзакциональной файловой системы. Те же structured storage работают также. Если сделаешь так, то будет гарантироваться целостность логического файла не зависимо от того, обеспечивает или нет транзакциональность сама файловая система.


 
Alex Konshin ©   (2005-04-26 10:01) [32]

Какого рода изменения происходят в данных?
Что-то изменяется или только добавляется?

Кстати, очень простую базу в своем файле можно организовать используя то обстоятельство, что можно создавать свои win32  регистри файлы и подключать их к системному регистри. Кстати, надо бы проверить, когда именно происходит изменение состояния регистри, при каждой операции или при закрытии ключа.
То есть, если изменения очень маленькие, то можно использовать регистри как древовидную базу данных. Ну, это, скажете вы, каждый знает. Но не каждый помнит о том, что можно иметь регистри в своем файле.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/regloadkey.asp


 
Sha ©   (2005-04-26 10:25) [33]

> Alex Konshin ©   (26.04.05 09:47) [31]
> Весь твой файл нужно открывать без кеширования
> или, еще лучше, организовать memory mapping.

Разве memory mapping гарантирует обновление секторов файла
в порядке обновления секторов в кеше?


 
Sha ©   (2005-04-26 10:26) [34]

В смысле "страниц в памяти" ?


 
mgcr ©   (2005-04-26 10:31) [35]

Суслик ©   (25.04.05 18:51) [29]

Тогда колись дальше: сколько должно быть таких "больших файлов", как они организованы (есть ли ключевые атрибуты и т.д.), как регулярно происходит запись.

От транзакций тебе все равно никуда не деться.
И потом, чем тебе мой или Алекса способ не нравится ?


 
Sha ©   (2005-04-26 10:43) [36]

> mgcr ©   (26.04.05 10:31) [35]
> И потом, чем тебе мой или Алекса способ не нравится ?

Тем, что способ [27] не гарантирует надежной работы.


 
Alex Konshin ©   (2005-04-26 11:30) [37]

Sha ©   (26.04.05 10:25) [33]

> Alex Konshin ©   (26.04.05 09:47) [31]
> Весь твой файл нужно открывать без кеширования
> или, еще лучше, организовать memory mapping.

Разве memory mapping гарантирует обновление секторов файла
в порядке обновления секторов в кеше?


Может я и не прав, но мне кажется это решается:


CreateFileMapping

SEC_NOCACHE   Sets all pages of a section to non-cashable.

Applications should not use this flag except when explicitly required for a device. Using the interlocked functions with memory mapped by a SEC_NOCACHE section can result in an EXCEPTION_ILLEGAL_INSTRUCTION exception.

SEC_NOCACHE requires either the SEC_RESERVE or SEC_COMMIT to be set.


 
Игорь Шевченко ©   (2005-04-26 11:52) [38]

Sha ©   (26.04.05 10:43) [36]


> Тем, что способ [27] не гарантирует надежной работы.


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


 
Sha ©   (2005-04-26 11:52) [39]

> Alex Konshin ©   (26.04.05 09:47) [31]
> Потом изменяешь соответствующий гиперблок (пишешь в него номер
> нового сектора данных) и опять-таки пишешь его на новое место.

Кстати, когда делал нечто подобное, чтобы обеспечить возможность
параллельной работы с несколькими файлами в файловой системе,
блоки FAT обновлял сразу по месту и вел отдельно список начал
подвешенных цепочек.

> Alex Konshin ©   (26.04.05 11:30) [37]
> CreateFileMapping

Как я понял, тут начало важнее, чем конец:

All pages of a section are to be set as non-cacheable.
This attribute is intended for architectures requiring various
locking structures to be in memory that is never fetched into
the processor"s. On 80x86 and MIPS machines, using the cache for
these structures only slows down the performance as the hardware
keeps the caches coherent.


Т.е. речь вроде идет о неизменяемых процессором данных.


 
Sha ©   (2005-04-26 12:03) [40]

> Игорь Шевченко ©   (26.04.05 11:52) [38]
> Если не секрет, в чем именно ненадежность
> и в какой ситуации эта ненадежность себя проявит.

Файловая система Windows имеет право обновлять данные на диске,
сбрасывая кэш, в произвольной последовательности.
Поэтому при отключении питания мы не можем гарантировать, что данные будут обновлены в обоих файлах. Индикатор может быть выставлен, а данные еще не записаны. При включении питания мы вполне можем обнаружить вместо данных файл нулевой длины.


 
Суслик ©   (2005-04-26 12:12) [41]


>  [35] mgcr ©   (26.04.05 10:31)


> И потом, чем тебе мой ... способ не нравится ?

Может и нравится. Но интересно знать авторитетное мнение, чем мой способ из [28] хуже?

Способ Алекса я пока не изучал.

Господа.

1. Ответ на вопрос Игоря по поводу количества файлов.
Файлов мало. Каждый файл записывается в среднем раз в 10 мин. Причем! В 3 мб это "край". 90 процентов времени файл не более 1мб или того меньше.

2. Что общественность думает над способом из [28]? И в ntfs и в fat?


 
mgcr ©   (2005-04-26 12:24) [42]


> Файловая система Windows имеет право обновлять данные на
> диске,
> сбрасывая кэш, в произвольной последовательности.
> Поэтому при отключении питания мы не можем гарантировать,
> что данные будут обновлены в обоих файлах. Индикатор может
> быть выставлен, а данные еще не записаны. При включении
> питания мы вполне можем обнаружить вместо данных файл нулевой
> длины.


Если бы все было так плохо, любая СУБД и любая файловая система гарантировано теряли бы свои данные при отключении питания. Однако же, не всегда теряют. Кроме того, при записи я предлагал сбрасывать буфер перед созданием файла, индицирующего завершение записи.


 
Суслик ©   (2005-04-26 12:28) [43]

Я тут подумал, что надо описать, что вообще делается.

Есть продукт, производит и распространяет его наша фирма (www.vkkb.ru).

Данный продукт последний раз был обновлен в 2001 году. В связи с неослабевающим интересом к продукту его нужно обновить.

Требования такие:
1. Клиент/сервер - 1 сервер, до 10 клиентов, каждый из которых примерно раз в 20 сек спрашивает у сервера маааленкую часть информации.
2. Минимальные требования к оборудованию и админу.
3. Отстутствие необходимости что-то дополнительно ставить и администрить.
4. Использовать TCP\IP, т.е. без всяких сторонних разработок.

Естестно, данные нужно хранить. Требуется, чтобы вероятность сбоя при выключении компа была минимальной. В принципе целевым пользователем является ВУЗЫ, а они достаточно бедные. Поэтому у них частно одноранговая сеть из 98. Там тоже должно работать.


 
Sha ©   (2005-04-26 12:33) [44]

> mgcr ©   (26.04.05 12:24) [42]
> Если бы все было так плохо, любая СУБД и любая файловая
> система гарантировано теряли бы свои данные при отключении
> питания. Однако же, не всегда теряют.

Гарантированно не теряют, только если используют
механизм прямой записи на диск.

> Кроме того, при записи я предлагал сбрасывать буфер перед
> созданием файла, индицирующего завершение записи.

Буфер сбрасывается всего лишь в кэш, а не в файл.


 
alpet ©   (2005-04-26 12:38) [45]

FlushFileBuffers тебе необходима для обоих файлов - и основного бинарного и описательного. Вместе с задержкой зто даст относительно неплохую надежность. Впрочем ничто не мешает устроить и несколько экспериментов.


 
Суслик ©   (2005-04-26 12:41) [46]

Александр, так что делать то? Как жить?

На самом деле супер-пупер надежность не нужна. Т.е. конечно я не полезу в низкоуровневое программирование режима ядра и прочего.

Нужно что-то разумное :)


 
alpet ©   (2005-04-26 12:44) [47]

2 Sha

Гарантированно не теряют, только если используют
механизм прямой записи на диск


Такой механизм в API похоже не существует. У большинства жестких дисков IDE есть кэш 2-8 мбайт. Когда и как он сбрасывается узнать программно имхо никак.


 
Суслик ©   (2005-04-26 12:45) [48]


>  [45] alpet ©   (26.04.05 12:38)


> не мешает устроить и несколько экспериментов.

Ты думаешь я смею постить их не устроив? :) Почему и впорос про terminateProcess возник - сначала хотел им моделировать сбой. Не вышло.

Потом даже пару раз доба комп из сети выдернул. Все работало. Но я думаю, что в момент нужные не попал. Сам поинимаешь - свой комп жалко. Сейчас на работе собирают тестовую машину с образами 98, xp и 2000. Буду ее мучать.

Наш сотрудник вспомнил, что у него диплмная работа была - ... что-то... там и контроллер выключения компа. Мы тут решили к этой тестовой машине это контроллер прикрутить. Пусть ночами падает, а потом проверяет себя :))


 
mgcr ©   (2005-04-26 12:46) [49]

Sha ©   (26.04.05 12:33) [44]


> Гарантированно не теряют, только если используют
> механизм прямой записи на диск.



> Буфер сбрасывается всего лишь в кэш, а не в файл.


"The WriteFile and WriteFileEx functions typically write data to an internal buffer that the operating system writes to disk on a regular basis. The FlushFileBuffers function writes all of the buffered information for the specified file to disk.

To open a file for unbuffered I/O, call the CreateFile function with the FILE_FLAG_NO_BUFFERING flag. This prevents the file contents from being cached. However, the file metadata may still be cached. To flush the metadata to disk, use FlushFileBuffers."

Это из ремарков к FlushFileBuffers.

Суслик ©   (26.04.05 12:41) [46]


> На самом деле супер-пупер надежность не нужна.


Тогда не мучайся. А то, согласно известному закону: "система обеспечения надежности выведет из строя все остальные системы".


 
alpet ©   (2005-04-26 12:49) [50]

Имхо здесь все-таки достаточно CRC.
Примерный алгоритм может такой:
1. Записывается весь файл, вызывается FlushFileBuffers.
2. Рассчитывается CRC для записанных данных и пишется вместе с именем файла в другой файл.

При считывании можно будет убедится что данные в первом файле не повреждены (в т.ч. вирусами, повреждениями диска на физическом уровне и т.д.), заново рассчитав CRC и сравнив с той что записана во втором файле.


 
Sha ©   (2005-04-26 12:53) [51]

> Суслик ©   (26.04.05 12:28) [43]

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


 
alpet ©   (2005-04-26 12:54) [52]

Суслик ©   (26.04.05 12:45) [48]

Не переживет он той ночи :). Так жестоко ни к чему, можно и программно спровоцировать сбой, без аппаратного вмешательство. Я здесь на форуме где-то приводил неправильный код с участием GetDIBits который довольно резко перезагружал Windows XP+SP2 без вопросов (у меня были даже ошибки в файла).


 
Sha ©   (2005-04-26 13:06) [53]

> alpet ©   (26.04.05 12:44) [47]
> Такой механизм в API похоже не существует.

FILE_FLAG_WRITE_THROUGH

> У большинства жестких дисков IDE есть кэш 2-8 мбайт. Когда и
> как он сбрасывается узнать программно имхо никак.

Забота производителя сбросить кэш на диск при отключении питания.

> mgcr ©   (26.04.05 12:46) [49]

Ну и что из этого следует?

> Суслик ©   (26.04.05 12:41) [46]
> Александр, так что делать то? Как жить?

[51]


 
Суслик ©   (2005-04-26 13:07) [54]


>  [51] Sha ©   (26.04.05 12:53)


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

Можно подробней? :)
Я в принциее так и делаю в 28, кроме работы с оглавлением. Что такое оглавление?


 
Sha ©   (2005-04-26 13:13) [55]

> Суслик ©   (26.04.05 13:07) [54]
> Я в принциее так и делаю в 28, кроме работы с оглавлением.
> Что такое оглавление?

Каталог, директорий, FindFirst :)

Вкралась очепатка: повторить чтение элемента, если размер файла нулевой


 
Sha ©   (2005-04-26 13:23) [56]

Еще две: повторять чтение элемента, пока размер файла нулевой


 
Alex Konshin ©   (2005-04-26 13:25) [57]

Sha ©   (26.04.05 11:52) [39]
> Alex Konshin ©   (26.04.05 09:47) [31]
> Потом изменяешь соответствующий гиперблок (пишешь в него номер
> нового сектора данных) и опять-таки пишешь его на новое место.
Кстати, когда делал нечто подобное, чтобы обеспечить возможность
параллельной работы с несколькими файлами в файловой системе,
блоки FAT обновлял сразу по месту и вел отдельно список начал
подвешенных цепочек.

Это потому, что ты использовал цепочки, а не гиперблоки. Гиперблоки в этом плане существенно надежнее и проще. Честно говоря, я не знаю, как устроена NTFS, но знаю FAT (которая цепочечная) и знаю файловую систему CMS из VM SP (которая гиперблочная). И я слышал, что при создании OS/2 IBM пошла именно по второму пути, потому думаю, что у NTFS оттуда же ноги растут.

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

Как я понял, тут начало важнее, чем конец:

All pages of a section are to be set as non-cacheable.
This attribute is intended for architectures requiring various
locking structures to be in memory that is never fetched into
the processor"s. On 80x86 and MIPS machines, using the cache for
these structures only slows down the performance as the hardware
keeps the caches coherent.

Т.е. речь вроде идет о неизменяемых процессором данных


Не знаю откуда ты это взял - на msdn этого нет. В описании функции именно то, что я написал.
И потом, вполне возможно, что нужно просто еще при CreateFile запросить некеширования, может этого и будет достаточно. Я уверен, что это решается, потому что базы всегда мапятся на память и с ними были бы проблемы, если бы это не решалось.


 
alpet ©   (2005-04-26 13:30) [58]

Sha ©   (26.04.05 13:06) [53]
FILE_FLAG_WRITE_THROUGH

Instructs the system to write through any intermediate cache and go directly to disk.

Во общем это альтернатива FlushFileBuffers полностью исключающая появления данных в системном кэше, но имхо при записи в несколько приемов (вызовов WriteFile) на производительность (немного) повлияет не в лучшую сторону.


 
Sha ©   (2005-04-26 13:35) [59]

> Alex Konshin ©   (26.04.05 13:25) [57]
> Это я к тому, что цепочечную файловую систему трудно сделать надежной

Делал, и даже на ЕС.

> Не знаю откуда ты это взял - на msdn этого нет.

From Borland D6 Help , а они у MS.

> Я уверен, что это решается,
> потому что базы всегда мапятся на память

Хотелось бы узнать, как это сделать через mapping.
Представь, если обновление идет автоматически при каждом
обращении на запись к странице, то были бы жуткие тормоза.
Значит, они это делают ручками, или не используют mapping.


 
Sha ©   (2005-04-26 13:36) [60]

> alpet ©   (26.04.05 13:30) [58]
> на производительность (немного) повлияет не в лучшую сторону

за все надо платить


 
alpet ©   (2005-04-26 13:40) [61]

Sha ©   (26.04.05 13:36) [60]

Согласен. Но где преимущество, за которое платить надо?
Использование FlushFileBuffers позволяет использовать кэш даже если файл записывается маленькими кусочками, и ничуть не влияет на производительность при чтении. Тогда как прямой доступ всего этого лишен.


 
mgcr ©   (2005-04-26 13:55) [62]

Sha ©   (26.04.05 13:06) [53]


> Ну и что из этого следует?


Да там в ремарках слово "диск" употребляется. А не кэш...


 
Sha ©   (2005-04-26 13:56) [63]

> alpet ©   (26.04.05 13:40) [61]
> Согласен. Но где преимущество, за которое платить надо?

Данные на диске всегда в согласованном состоянии.


 
alpet ©   (2005-04-26 14:03) [64]

Sha ©   (26.04.05 13:56) [63]
>Данные на диске всегда в согласованном состоянии.

Поясни пожайлуста отличия - если файл размером 1мб записывается с участием системного кэша и сбрасывается FFB или если он же пишется напрямую. Как это отражается на файле и надежности его записи ?


 
Alex Konshin ©   (2005-04-26 14:05) [65]

Sha ©   (26.04.05 13:35) [59]
> Alex Konshin ©   (26.04.05 13:25) [57]
> Это я к тому, что цепочечную файловую систему трудно сделать надежной
Делал, и даже на ЕС.

Все возможно для человека с интелектом, при желании и зайца можно научить курить (c)
Еще скажи, что это было просто. Я кстати, тоже делал, правда так и не реализовали до конца - проект умер, да и ЕС тоже.
В цепочка проблема в том, что при обновлении нескольких блоков в одной транзакции нужно обновлять сразу много блоков FAT в непонятном порядке, получается проще сбрасывать его весь. Отсюда получаются две копии FAT. Конечно, можно попытаться это оптимизировать, но сделать это надежно сложно. Я помню, что я тоже какие-то дополнительные цепочки вводил, но тонкостей в упор не помню.

По поводу маппинга: по косвенным признакам видно, что на mapview влияют аттрибуты открытия файла:
When flushing a memory-mapped file over a network, FlushViewOfFile guarantees that the data has been written from the local computer, but not that the data resides on the remote computer. The server can cache the data on the remote side. Therefore, FlushViewOfFile can return before the data has been physically written to disk. However, you can cause FlushViewOfFile to return only when the physical write is complete by specifying the FILE_FLAG_WRITE_THROUGH flag when you open the file with the CreateFile function.

Я думаю, что в MS SQL либо вообще пользуются недокументироваными задними дверями, либо просто создают вью и флашают их когда надо. Проблема отключения питания их не волнует - нужно имет UPS на серверах, что, в принципе, верно.
Кстати, это можно проверить. У кого под рукой есть MS SQL сервер?  Посмотрите в WinObj какие объекты в памяти создаются. Нет ли там кучки секций?
Видно не даром MS SQL умеет свою партишн создавать. Видимо и из-за этого тоже.


 
Sha ©   (2005-04-26 14:29) [66]

> mgcr ©   (26.04.05 13:55) [62]

Только FILE_FLAG_WRITE_THROUGH дает гарантию при работе в сети.


> alpet ©   (26.04.05 14:03) [64]

Тут вот какое дело.
Если ты работаешь с локальным файлом один и хочешь по завершении какой-то работы отразить результаты на диске, то FlushFileBuffers предпочтительнее. Но когда приложение работает с файлом в сети, или с локальным файлом, но обслуживает нескольких клиентов, данные которых должны сохраняться в произвольном порядке, то остается только FILE_FLAG_WRITE_THROUGH или свои буфера в комбинации с несколькими FlushFileBuffers, что по существу эквивалентно.

> Alex Konshin ©   (26.04.05 14:05) [65]
> По поводу маппинга...

Ага, тоже нашел уже FILE_FLAG_WRITE_THROUGH + FlushViewOfFile.


 
mgcr ©   (2005-04-26 14:46) [67]

Sha ©   (26.04.05 14:29) [66]


> Только FILE_FLAG_WRITE_THROUGH дает гарантию при работе
> в сети.


Гарантию чего, Саша ? Пакет IRP_MJ_FLUSH_BUFFERS отправится драйверу сетевого редиректора при вызове FlushFileBuffers, данные для сброса по моему разумению, должны находиться на удаленном компьютере (чтобы он когерентность обеспечивал с локальными открытиями файлов), поэтому, если питание отключится на удаленном компьютере во время операции, то данные не запишутся всяко, а если питание отключится на локальном, то потеря данных, по идее, должна зависеть от того, успел ли редиректор отправить сетевой пакет сброса на удаленный компьютер.
Или я где-то здорово ошибаюсь ?


 
Суслик ©   (2005-04-26 14:56) [68]

Господа.

Конкрентый вопрос - делал ли кто-то сам то, что мне нужно на win98 и win2000?


 
Sha ©   (2005-04-26 15:01) [69]

mgcr ©   (26.04.05 14:46) [67]
Вопрос в том, в какой момент к тебе вернется управление и что означает код возврата.
Без FILE_FLAG_WRITE_THROUGH, если не ошибаюсь, гарантируется только доставка данных до адресата, но не запись на его диск.


 
Sha ©   (2005-04-26 15:05) [70]

> Суслик ©   (26.04.05 14:56) [68]
> Конкрентый вопрос - делал ли кто-то сам то, что мне нужно на win98

Я делал.
Проверено в условиях сети.
Файл располагался на удаленной W98 или Novel(не помню какая).


 
Суслик ©   (2005-04-26 15:11) [71]


>  [70] Sha ©   (26.04.05 15:05)

Не, мне удаленно не надо. Мне исключительно локально, без всякой сети. Т.е.:
1. Бинарный файл (до 3 мб) локально
2. Файловая система - ntfs или fat.

Точно такое кто-то делал?


 
Sha ©   (2005-04-26 15:16) [72]

> Суслик ©   (26.04.05 15:11) [71]
Ну уж если удаленно работает, то локально обязано.


 
mgcr ©   (2005-04-26 15:24) [73]


> Конкрентый вопрос - делал ли кто-то сам то, что мне нужно
> на win98 и win2000?


Жаль, что мы так и не услышали начальника транспортного цеха.


 
alpet ©   (2005-04-26 15:44) [74]

Я всеже советую задуматься о применении CRC. Даже если все будет гладко записываться - повреждение файла после его записи исключать нельзя. Если рассчет контрольной суммы сложен - можно обойтись созданием копии файла (маловероятен сбой который одинаково испортит два файла).


 
mgcr ©   (2005-04-26 16:06) [75]

alpet ©   (26.04.05 15:44) [74]

Копий должно быть нечетное число. А если еще старину Хэмминга вспомнить...


 
Суслик ©   (2005-04-26 16:09) [76]


>  [73] mgcr ©   (26.04.05 15:24)


> Жаль, что мы так и не услышали начальника транспортного
> цеха.


Ты о чем? Какого цеха?


 
mgcr ©   (2005-04-26 16:14) [77]

Суслик ©   (26.04.05 16:09) [76]


> Конкрентый вопрос - делал ли кто-то сам то, что мне нужно
> на win98 и win2000?


А что тебе нужно, ты как гимназистка, объясняешь туманными полунамеками.


 
Суслик ©   (2005-04-26 16:23) [78]


>  [77] mgcr ©   (26.04.05 16:14)

Да я вроде все объяснил где-то выше.
Дабы не искать повторю:
Сохранение раз в 10 минут файла до 3 мб таким образом, чтобы при аппаратных сбоях (выключение компьютера) при последующем восстановлении либо было понятно, что произошел сбой (т.е. новый файл не дописался), либо новый файл дописался и информации о сбое нет. В первом случае происходит восстановление старого файла.

Т.е. либо все записалось, либо не записалось и откатилось до предыдущего значения с уведомлением о случившемся сбое заинтересованных сторон.

Должно работать в 98 и 2000, на ntfs и fat.


 
Sha ©   (2005-04-26 16:43) [79]

Суслик ©   (26.04.05 16:23) [78]

Если не в сети, то должно может будет достататочно FlushFileBuffers, как советовал mgcr ?


 
Суслик ©   (2005-04-26 16:51) [80]


> Если не в сети, то должно может будет достататочно FlushFileBuffers,
> как советовал mgcr ?

Да я тоже так думаю, что достаточно.
Т.е. ты тоже думаешь, что достаточно?


 
mgcr ©   (2005-04-26 17:01) [81]

Суслик ©   (26.04.05 16:23) [78]


> Сохранение раз в 10 минут файла до 3 мб таким образом, чтобы
> при аппаратных сбоях (выключение компьютера) при последующем
> восстановлении либо было понятно, что произошел сбой (т.е.
> новый файл не дописался), либо новый файл дописался и информации
> о сбое нет. В первом случае происходит восстановление старого
> файла


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


 
Sha ©   (2005-04-26 17:20) [82]

> Суслик ©   (26.04.05 16:51) [80]
Можно проверить


procedure TSenderForm.Button1Click(Sender: TObject);
var
 fi: file;
begin
 AssignFile(fi,"aaa"); Rewrite(fi,1);
 BlockWrite(fi,"bbb",3);
 //FlushFileBuffers(TFileRec(fi).Handle);
 ShowMessage("ccc");
 CloseFile(fi);
end;


Пускаем как есть, OK не говорим.
Под 98 размер файла должен быть 0.
Говорим OK - размер меняется на 3.
Значит метаданные в оглавлении обновляются по Close.

Повторяем с раскомментированным FlushFileBuffers.
Видим, что метаданные обновлены до Close.
Все как ты хотел.


 
alpet ©   (2005-04-26 17:22) [83]

Маленький итог:
1. Необходимо - сбрасывать данные на жесткий диск принудительно.
Самое простое для этого использовать функцию FFB (FlushFileBuffers).
2. После завершения этой операции создавать дополнительный файл как доказательство что первый уже записался.
3. Дополнительно: Как защиту от непредвиденных ситуаций можно создавать копию первого файла.

Что еще не хватает для решения задачи?


 
Sha ©   (2005-04-26 17:31) [84]

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


 
mgcr ©   (2005-04-26 17:35) [85]

Sha ©   (26.04.05 13:35) [59]

<offtopic>

> > Это я к тому, что цепочечную файловую систему трудно сделать
> надежной
>
> Делал, и даже на ЕС.


Был во время оно на ЕС такой продукт Librarian (отечественный вариант носил название "Ритм") со всякими Jobstream-файлами и аккурат цепочечной организацией внутренних файлов данных, в отличие от экстентной.
Не знакомо ?

</offtopic>


 
Sha ©   (2005-04-26 17:38) [86]

> alpet ©   (26.04.05 17:22) [83]
Вроде п.п. 2 и 3 лишние


 
Sha ©   (2005-04-26 17:41) [87]

> mgcr ©   (26.04.05 17:35) [85]
> Был во время оно на ЕС такой продукт Librarian...
> Не знакомо ?

Неа, у меня был свой...


 
Суслик ©   (2005-04-26 17:42) [88]


>  [86] Sha ©   (26.04.05 17:38)
> > alpet ©   (26.04.05 17:22) [83]
> Вроде п.п. 2 и 3 лишние

как раз вопрос о транзакционности flushfilebuffer. Может быть пока идет скидывание комп упадет и не скинется до конца - половина новая, половина старая. Где гарантия, что этого не будет?


 
alpet ©   (2005-04-26 17:44) [89]

Sha ©   (26.04.05 17:38) [86]
2. Как иначе доказать что файл был записан полностью, а не частично?
3. Это только метод перестраховки (вирусы, проблемы с жестким диском).


 
alpet ©   (2005-04-26 17:47) [90]

Суслик ©   (26.04.05 17:42) [88]
Пока FFB скидывает содержимое буферов на диск - управление не вернется. Если после ее отработки закрыть описатель файла, и создать второй (копию 1:1) и обойтись с ним так же, о наличии сбоя можно будет судить по отсутствию второго файла (до него просто дело не дойдет) либо по наличию отличий между вторым и первым файлом.


 
mgcr ©   (2005-04-26 17:53) [91]


> Может быть пока идет скидывание комп упадет и не скинется
> до конца - половина новая, половина старая. Где гарантия,
> что этого не будет?


В End-Of-File pointer


 
Суслик ©   (2005-04-26 17:57) [92]


>  [91] mgcr ©   (26.04.05 17:53)

таки ты хочешь сказать, что система обо мне сама позаботится, сбой произойдет при FlushFileBuffers, то при сосстановлении система восстановит исходное значение файла?

Не верю, быть такого не может. А если файл 1гб?

Или ты что-то другое имел в виду?


 
Sha ©   (2005-04-26 17:58) [93]

alpet ©   (26.04.05 17:44) [89]

Возможны 3 состояния:
a) есть только файл data.txt,
б) есть файл data.txt и data.tmp,
в) есть только файл data.tmp.

В случаях а) и б) - правильный файл data.txt.
В случае в) - правильный файл data.tmp. Переименовываем и продолжаем работать.


 
alpet ©   (2005-04-26 18:02) [94]

Sha ©   (26.04.05 17:58) [93]
Четвертое состояние:
г) Есть только файл data.txt но он безнадежно поврежден.

Как быть?


 
Sha ©   (2005-04-26 18:19) [95]

> Суслик ©   (26.04.05 17:57) [92]

Эксперимент (на W2K) подтверждает, что FlushFileBuffers - синхронная операция, и управление к тебе не вернется до завершения записи данных и метаданных на диск:


procedure TSenderForm.Button1Click(Sender: TObject);
var
 fi: file;
 i: integer;
 s: string;
begin
 SetLength(s,1024);
 AssignFile(fi,"aaa"); Rewrite(fi,1);
 for i:=1 to 1024*1024 do BlockWrite(fi,s[1],Length(s));
 FlushFileBuffers(TFileRec(fi).Handle);
 ShowMessage("ccc");
 CloseFile(fi);
end;


Пускаем сие чудо, а файлик смотрим Far"ом.

> alpet ©   (26.04.05 18:02) [94]
> г) Есть только файл data.txt но он безнадежно поврежден.

наша приграмма ни при каких условиях сделать этого не могла.


 
alpet ©   (2005-04-26 18:32) [96]

Sha ©   (26.04.05 18:19) [95]

> наша приграмма ни при каких условиях сделать этого не могла.


Это понятно. Но другая программа вполне может повредить файл. И жесткий диск может внезапно осыпаться битыми кластерами.


 
mgcr ©   (2005-04-26 18:47) [97]

alpet ©   (26.04.05 18:32) [96]

А еще может случиться пожар и наводнение. Одновременно. Задача не стоит того флейма.


 
Суслик ©   (2005-04-26 18:54) [98]


>  [95] Sha ©   (26.04.05 18:19)


Таки что это доказывает?
Маленькое уточняющее резюме - ты считаешь, что функция flushFileBuffers будучи вызванной гарантирует, что файл будет записан даже если питание будет отключено? Запустался я что-то в высказываниях (((


>  [97] mgcr ©   (26.04.05 18:47)
> Задача не стоит того флейма.


Предлагаю автору топика решать, что стоит его задача.


 
alpet ©   (2005-04-26 18:55) [99]

mgcr ©   (26.04.05 18:47) [97]
Ну стихийные бедствия я думаю нельзя предотвратить. Да и вирусов в порядке вещей повреждающих файлы мало. Так что с учетом отсутствия этих факторов, копии не нужны.

<offtop>
А какая тема - рекордсмен по количеству постов.


 
Суслик ©   (2005-04-26 18:57) [100]

В общем, ладно. Спасибо всем за участие к проблеме.
Завтра у меня будет тестовый комп с образами разных систем и разными файловыми системами. Потестирую методику:
1.Переименовывать файл "что-то.dat" в "что-то.old"
2.Писать в "что-то.dat"
3.Делать flushFileBuffers для "что-то.dat"
4.Потом удалять "что-то.old"
5.Если при загрузке системы есть "что-то.old", то был сбой.

Об успехах доложу:)


 
alpet ©   (2005-04-26 19:02) [101]

Суслик ©   (26.04.05 18:54) [98]

Если управление вернулось из функции - питание еще наличествует и файл уже на диске (на худой конец в кэше hdd). Если не вернулось (питание пропало или кто-то нажал Reset) - файл не записался до конца, при этом на диске он будет выглядеть либо как пустой, либо вообще отсутствовать.

Кстати выявляется вопрос - на сигнал Reset HDD сбрасывает аппаратный буфер или же записывает его на диск.


 
Sha ©   (2005-04-26 19:05) [102]

>Sha ©   (26.04.05 18:19) [95]
Вообще-то приведенный код не позволяет сделать
никаких выводов, т.к. Far получает уведомления с опозданием.

А если попробовать использовать FindFirst, то sr.Size
будет один и тот же независимо от вызова/невызова FlushFileBuffers, т.к. метаданные тоже кешируются.
В синхронность остается только верить...


 
Sha ©   (2005-04-26 19:14) [103]

> Суслик ©   (26.04.05 18:54) [98]
Точнее так:
на мой взгляд, для локального файла возрат из FlushFileBuffers гарантирует, что данные и метаданные будут записаны на диск даже если питание будет отключено до вызова CloseHandle.


 
Суслик ©   (2005-04-26 19:24) [104]


>  [103] Sha ©   (26.04.05 19:14)


т.е. отслюда следует вывод, что если я после возврата из flushFileBuffers удалю копию файла, то я гарантированно данные записал. Так?

Т.е. моя методика, описанная выше:
1.Переименовываю файл "что-то.dat" в "что-то.old"
2.Пишу в "что-то.dat"
3.Делаю flushFileBuffers для "что-то.dat"
4.Потом удалаю "что-то.old"
5.Если при загрузке системы есть "что-то.old", то был сбой. Тогда в качество "что-то.dat" нужно взять "что-то.old".

имеет правод на жизнь?


 
Суслик ©   (2005-04-26 19:25) [105]


>  [104] Суслик ©   (26.04.05 19:24)

Вернее не гаратированно не записал, а гарантированно не потерял.


 
Sha ©   (2005-04-26 19:46) [106]

> Суслик
> имеет право на жизнь?

Вроде имеет :)

Но получше будет так:
- писать что-то.tmp,
- удалять что-то.dat,
- переименовывать что-то.tmp в что-то.dat.
В этом случае время жизни "неправильного" имени меньше.


 
Суслик ©   (2005-04-26 20:10) [107]


> - переименовывать что-то.tmp в что-то.dat.

ой боюсь я за эту операцию :)))


 
Суслик ©   (2005-04-26 20:10) [108]

правда она и у меня есть... так что может так и сделаю. Наверно лучше всего копировать файл, а не переименовывать. В этом случае вообще очень все надежно будет.


 
Sha ©   (2005-04-26 21:23) [109]

> Суслик ©   (26.04.05 20:10) [108]
> Наверно лучше всего копировать файл, а не переименовывать.

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


 
Суслик ©   (2005-04-27 01:11) [110]


> Sha ©   (26.04.05 21:23) [109]

При всем уважении, Саша, ты не писал систему - фиг ее знает, что тут атомарная операция, а что нет.

Я думаю, что лечше всего полагаться ни минимизирование (а не исключение) вероятности ошибки.


 
Sha ©   (2005-04-27 09:36) [111]

> Суслик ©   (27.04.05 01:11) [110]

В любой файловой системе переименование файла - атомарная операция.


 
mgcr ©   (2005-04-28 10:20) [112]

Суслик ©   (27.04.05 01:11) [110]


> Я думаю, что лечше всего полагаться ни минимизирование (а
> не исключение) вероятности ошибки.


Лучше каждый оператор с молитвой писать. Оно надежнее. А еще лучше - послушать или почитать умных людей. Они тебе вреда не хотят.


 
Суслик ©   (2005-04-29 12:35) [113]


> В любой файловой системе переименование файла - атомарная
> операция.

верю :) Это документировано?


>  [112] mgcr ©   (28.04.05 10:20)

хватит колкости говорить, я и тебя и Сашу слушаю, и не сомневаюсь в вашем уме.


 
Sha ©   (2005-04-29 14:05) [114]

> Суслик ©   (29.04.05 12:35) [113]

>> В любой файловой системе переименование файла - атомарная
>> операция.

> верю :) Это документировано?

А ты можешь представить себе наполовину переименованный файл? :)


 
Суслик ©   (2005-04-29 15:41) [115]


>  [114] Sha ©   (29.04.05 14:05)


"чудеса бывают"
(с) опытный программист (где-то вчера прочел)

Длинные строки в дельфи потокобезопасные. ДинМассивы тоже. Т.е. это значит, что строка не будет неконсистентной (с системной точки зрения) при многопоточном использовании - например, не оказется, что длина строки, одна а на самом деле выделено памяти другое количество. Также и с массивами.

Но это же ребята из борланда потрудились. Не сделай они этого - валились бы строки из нескольких потоков с нашими любимыми AV. Запросто.

Наверняка в файлах авторы тоже потрудились. Так, чтобы данные не смогли остаться неконсистентными при выключении. Весь вопрос - где про это написано.


 
mgcr ©   (2005-04-29 15:46) [116]


> Весь вопрос - где про это написано.


Ты эта...не притворяйся write only, если не трудно. Пост № 13 прочитай.


 
Суслик ©   (2005-04-29 15:49) [117]


>  [116] mgcr ©   (29.04.05 15:46)

така вы не скажете где это написано?! (шутка, читать я тоже умею).
..........................

Списибо всем. Собираюсь купить указанную Игорем книгу.


 
Sha ©   (2005-04-29 16:13) [118]

> Суслик ©   (29.04.05 15:41) [115]
> Весь вопрос - где про это написано.

Цитата из неизданного MS:

Предостередение.
Операция переименования файла в пределах одного каталога
относится к классу потенциально опасных.
Внезапное пропадание электропитания может привести к потере
файла или появлению второго имени у одних и тех же данных.


 
Суслик ©   (2005-04-29 16:14) [119]


>  [118] Sha ©   (29.04.05 16:13)

Шутка? Ей богу, юмор я люблю, но мне сейча не до него :)


 
Sha ©   (2005-04-29 16:25) [120]

Цитата из неизданного MS.


 
alpet ©   (2005-04-29 16:33) [121]

Если свести изменение имени файла к физическому процессу - это передача в буфер данных для как минимум одного сектора из системной области (Root Directory?). Можно быть уверенным в атомарности этой операции, поскольку жесткий диск не начнет записи, пока все заявленные данные не будут переданны в его кэш. По исчезновении питания HDD наверняка успеет записать переданные данные в кэш (ему при наихудших раскладах на все надо примерно 1/8 секунды), если запись уже начата.


 
Sha ©   (2005-04-29 16:39) [122]

> alpet ©   (29.04.05 16:33) [121]
> По исчезновении питания HDD наверняка успеет записать переданные данные в кэш

Обязан успеть, иначе данные на диске будут физически разрушены.
Т.е. либо не начнет, либо закончит.


 
Суслик ©   (2005-04-29 16:42) [123]


>  [122] Sha ©   (29.04.05 16:39)

я в полном ступоре. Ты с одной стороны цитируешь потенциальную опастность переименования, с другой - говоришь, что "обязан успеть". Я что-то не понимаю (


 
Sha ©   (2005-04-29 16:49) [124]

Суслик ©   (29.04.05 16:42) [123]

Цитирую неизданное MS. Могу процитировать что-нибудь неизданное тобой, могу процитировать даже ненаписанное.
Чуть выше я говорил об атомарности переименования файла в прелелах каталога.
Вроде тут нет противоречия.


 
Sha ©   (2005-04-29 17:22) [125]

> Суслик ©   (29.04.05 16:42) [123]

Физически изменения в каталоге при переименовании или удалении файла (8.3) сводятся к перезаписи одного сектора. Сектор нельзя записать наполовину.

В отношении цитат. Из ненаписанного тобой:
"Все файловые системы MS прекрасно описаны и абсолютно надежны.
Не существует проблем с пониманием логики их работы и восстановлением после сбоев".


 
alpet ©   (2005-04-29 17:33) [126]

Что-бы окончательно успокоить - если каким-то чудом запись сектора прервется - данные с него прочесть попросту не удаться. Насколько я помню они апаратно защищены CRC - и при несовпадении контрольной суммы жесткий диск может вполне решить что сектор поврежден, и пометит его соответствующим образом (восстановить конечно можно будет его обычным форматированием). А система увидев такие повреждения в системной области ROOT, скорее всего пропавшие файлы (имен в секторе может быть несколько) обнаружит при проверке и назовет типа file001.chk. Так-что переименование можно считать операцией безопасной - либо будет файл с новым именем, либо не будет но это очень маловерятно.


 
Sha ©   (2005-04-29 17:40) [127]

> alpet ©   (29.04.05 17:33) [126]
> Что-бы окончательно успокоить - если каким-то чудом запись
> сектора прервется - данные с него прочесть попросту не
> удаться. Насколько я помню они апаратно защищены CRC

Пропадание питания - штатная ситуация.
Есть мнение, что современные жесткие диски не только успевают
закончить незавершенные операции, но и увести головки в область
парковки.


 
mgcr ©   (2005-04-29 20:32) [128]

Sha ©   (29.04.05 17:40) [127]


> что современные жесткие диски не только успевают
> закончить незавершенные операции, но и увести головки в
> область
> парковки.


Там эта...конденсатор стоит...Ну и в блоке питания тоже...Даже два...

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

Суслик ©   (29.04.05 16:42) [123]

А по поводу безопасности переименования, ты попробуй представить себе ситуацию пропадания питания во время операции переименования и все ее последствия. Даже не читая Руссиновича с братом его во Христе Соломоном. Просто для себя представь, что может произойти и сделай выводы.


 
Alex Konshin ©   (2005-05-01 05:35) [129]

Sha ©   (29.04.05 17:22) [125]
> Суслик ©   (29.04.05 16:42) [123]
Физически изменения в каталоге при переименовании или удалении файла (8.3) сводятся к перезаписи одного сектора.

Ты неправ. Как минимум двух. Оглавление никогда не пишется по месту. А потому будет изменен по крайней мере еще один блок, который содержит ссылку на блок оглавления, и далее - рекурсивно к корню. Это будет как и в случае цепочечных, так и гиперблоковых FS.


 
Sha ©   (2005-05-01 12:51) [130]

> Alex Konshin ©   (01.05.05 05:35) [129]

Общая идеология понятна.

Однако, нет уверенности, что разработчики не использовали
возможность оптимизации для имен формата 8.3, которые всегда
помещаются в одном блоке.

Не скажу точно, как на самом деле - очень давно рылся в
исходниках DOS.


 
mgcr ©   (2005-05-01 17:37) [131]

Alex Konshin ©   (01.05.05 05:35) [129]
Sha ©   (01.05.05 12:51) [130]

Что будет при переименовании файла в FAT я не знаю, а вот в NTFS перепишется один блок MFT (размером в один килобайт) и занесется одна запись в журнал транзакций NTFS. Итого - несколько операций ввода вывода (одна отложенная - запись блока MFT)


 
Alex Konshin ©   (2005-05-02 05:17) [132]

Во всех FS, что я знаю запись измененного блока всегда идет на новое место. В NTFS наверняка тоже, т.к. во-первых, это правильно, во-вторых иначе не было бы возможности откатить транзакцию. Так как пишем в другое место, то обязательно будет изменен как минимум еще один блок, который указывает на измененый. Будет ли это гипреблок или блок в FAT (или как он называется в той FS) - неважно. Так как изменяется этот гиперблок, то также будет изменен гиперблок, указывающий на него, и так по рекурсии.
Вот именно об этом я и написал. Неужели это не очевидно?


 
Sha ©   (2005-05-02 10:21) [133]

> Alex Konshin ©   (02.05.05 05:17) [132]

Конкретный пример. Удаление файла 8.3 в MS-DOS.
Т.е. необходимо изменить 1 байт в 1 секторе оглавления.
Работу с FAT опускаем, или считаем что FileSize=0.

Ты абсолютно уверен, что здесь не будет перезаписи
блока оглавления по месту?


 
Alex Konshin ©   (2005-05-03 05:07) [134]

В DOS, насколько я помню, две FAT. Я не проверял, но не удивлюсь, если перезаписи по месту не будет. Иначе зачем две FAT? Скорее всего будет изменятся неактивная FAT и только потом она становится активной. Сколько это потребует операций записи можешь сам посчитать.
Вообще-то хрен его знает, в DOS вполне могла быть запись по месту. Но ни на NTFS, ни на FAT32 так не получится хотя бы потому, что там имена переменной длины. Но обратное неверно: из того, что имена фиксированной длины совсем не следует, что будет перезапись по месту, например, в той же файловой системе CMS имена фиксированной длины, но перезаписи по месту там точно не было, это я знаю на 100%. Так что для меня еще не факт, что в DOS было не так, хотя и допускаю - там экономили на чем только можно.

Работу с FAT опускаем, или считаем что FileSize=0.
Причем тут FileSize? Оглавление само по себе тоже файл, а у него уж всяко размер ненулевой. Изменение любого файла не по месту (и оглавления в том числе) приводит к изменению FAT. Зачастую в файловых системах и сам FAT (или его аналог) тоже выглядит как файл. В гиперблочных FS в роли недоразвитой FAT выступает битовая таблица занятости секторов вместе с гиперблоками файла-оглавления. Можно, правда, отвести для всего FAT фиксированную область на диске (или несколько), тогда сам FAT будет обновляться по месту (по-моему в DOS так - я уже не помню). Но с оглавлением такой фокус не пройдет - оно просто обязано быть обычным файлом.


 
Sha ©   (2005-05-03 10:01) [135]

> Alex Konshin ©   (03.05.05 05:07) [134]
> В DOS, насколько я помню, две FAT.

Это я знаю. Только причем зесь это?
Обрати пожалуйста внимание, я везде говорю только о количестве
операций с оглавлением, а FAT не трогаю. Делаю это намеренно,
чтобы нагляднее показать, что запись по месту при работе с
оглавлением возможна и выгодна.

> Вообще-то хрен его знает, в DOS вполне могла быть запись по месту.

Вот и я о том же. А если писать огавление по месту, то изменять FAT при переименовании, очевидно, не потребуется.

> Оглавление само по себе тоже файл, а у него уж всяко размер
> ненулевой. Изменение любого файла не по месту (и оглавления в
> том числе) приводит к изменению FAT.

Это понятно, но это не наш случай. Мы правим по месту.

> Можно, правда, отвести для всего FAT фиксированную область на
> диске (или несколько), тогда сам FAT будет обновляться по
> месту (по-моему в DOS так - я уже не помню).

Именно так.

> Но с оглавлением такой фокус не пройдет - оно просто обязано
> быть обычным файлом.

Одно никак не следует из другого.
Во первых, сам так делал.
Во-вторых, как, по твоему, работали всевозможные FileRestore, NortonUtilities, восстанавливающие удаленные файлы. Да ты и сам мог сделать это при помощи DiskEditor"a, правя один сектор оглавления по месту (о FAT опять молчим).
А если можно обратно, то почему нельзя туда?

В общем, я думаю, не стоит учить друга, теорию мы оба знаем.

В этой ветке я, обращаясь к здравому смыслу автора, просто
попровал на пальцах показать ему атомарность операций с оглавлением.
Общий случай рассмотреть невозможно - файловых систем множество,
да и незачем обычному программисту вникать в детали их
реализации. Ими надо уметь правильно пользоваться.
А если интересно - он сам должен уметь находить нужную страниу.


 
Суслик ©   (2005-05-03 15:03) [136]

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


> А если интересно - он сам должен уметь находить нужную страниу.

я все умею, но на это нужно время. Поэтому решил воспользоваться форумом для личной экономии времени и не вижу в этом проблем. Да и топик такой содержательный и объемный получился, так это вообще хорошо - и форуму полезно:)



Страницы: 1 2 3 4 вся ветка

Форум: "WinAPI";
Текущий архив: 2005.06.29;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.91 MB
Время: 0.041 c
3-1116315431
stud
2005-05-17 11:37
2005.06.29
посоветуйте структуру таблицы


1-1117695588
Egor
2005-06-02 10:59
2005.06.29
Ассоциировать файл с программой


1-1117963373
Mihail
2005-06-05 13:22
2005.06.29
Глупейшая проблема


5-1087896935
Ярослав
2004-06-22 13:35
2005.06.29
Компоненты как в Win XP


1-1117738255
Profi
2005-06-02 22:50
2005.06.29
Проблема при использовании dll в качестве plugina





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский