делаю файловую базу данных... весь файл состоит из блоков фиксированной длины, в начале каждого блока - заголовок... столкнулся с такой странной вещью: после расширения файла некоторое время существенно тормозит функция WriteFile... чтобы было понятнее, рассмотрим пример: 1) при выделении и записи мегабайта блоков из уже существующих (размер файла не меняется) весь процесс занимает примерно 220 милисекунд... 2) при выделении и записи того же мегабайта блоков, дописывая блоки в конец файла (сначала размер файла увеличивается до необходимого размера, затем заполняется блоками) весь процесс замедляется до порядка 2 секунд... можете пояснить в чем может быть проблема? и как с этим можно бороться?
странно, что никто не откликнулся... возможно проблема с тем, каким образом я расширяю файл (SetFilePointerEx + SetEndOfFile)?
-вот этот момент непонятен. Вообще непонятно, причём здесь блоки. Вопрос нераскрыт. Например: и вот это: Связи не вижу, про блоки непонятно. Теперь возможное решение. Попробуй расширять файл путём дописывания нулей. И посмотри, будет тот же эффект или нет. Опять же. Если записываемые блоки должны идти подряд в файле, не пиши их по очереди, а формируй единый блок в памяти и пиши его целиком. Смотри на эффект.
файл физически состоит из блоков: Код (Text): <начало файла><блок 1>....<блок n><конец файла> блок фиксированной длины, у блока есть заголовок со служебными данными, блок может быть свободен (в него можно записывать), или занят (в него уже записаны ценные данные)... операция записи смотрит есть ли свободные блоки, и если они есть, то использует их, если свободных блоков не хватает, то файл расширяется на требуемое количество дополнительных блоков... затем производится запись... вроде понятно описано, теперь ближе к проблеме... для простоты возьмем тест, в котором необходимо записать 1 мегабайт данных в такой файл блочной структуры... если в файле достаточно свободных блоков для записи 1 мегабайта, то операция записи (в цикле поблочно с помощью функции WriteFile) занимает примерно 200 милисекунд... если все блоки в файле заняты, то файл расширяется на количество блоков, способное содержать 1 мегабайт данных... далее в начало каждого добавленного блока записывается заголовок блока (так же в цикле поблочно с помощью WriteFile), в этом цикле каждая итерация записи заголовка существенно медленнее каждой итерации записи данных в блок из предыдущего случая (примерно 16 милисекунд против 2 милисекунд)... я не могу понять с чем это связано, вроде в каждой итерацией данных пишется меньше (16 байт заголовка против 512 байт данных заголовка) аналогичным методом, шифрование не применяется и тд... после записи заголовков происходит та же самая запись данных, которая уже не тормозит... может это как то связано с изменением размера файла (изменение размера файла протекает очень быстро менее 2 милисекунд)? да, попробую...
-В вашем случае теоретически. Я читал/писал посекторно/поблочно (на уровне реальной ФС), получая параметры: BytesPerSector,SectorsPerTrack,PartitionLength и т.д. через DeviceIoControl (IOCTL_DISK_GET_DRIVE_GEOMETRY,IOCTL_DISK_GET_PARTITION_INFO)...
не придирайтесь к словам, это разные уровни абстракции... ЗЫ небольшое дополнение для тех, кто не понял с начала темы: ринг-3 оунли))
Rel Честно пытался вникнуть в написанное, но не хватило терпения (или сообразительности). Поэтому дам несколько общих рекомендаций. Во-первых, то что ты говоришь - файл имеет блочную структуру - это совершенно несущественно. Чтобы решить твою задачу, как мне кажется, нужно уйти от этой подробности и чётко уяснить, что файл - это последовательность байт на уровне жёсткого диска. Это важно. Второе. Когда у меня встала задача ведения лога при очень частой записи (там несколько тысяч раз в секунду), естественно, я столкнулся с тем, что процедура записи занимает очень много времени. Решение нашлось сразу, так как плавало на поверхности. Я писал не сразу в файл, а в память, и потом, когда размер "записанных" данных достигал 1МБ, к примеру, писал целиком на диск. В вашем случае сразу же смутило следующее - вначале пишутся заголовки блоков (о которых, кстати, ФС понятия не имеет. Для запись каждого заголовка означает - спозиционировать головку, записать данные). Естественно, если у вас в одном мегабайте 100 заголовков - это займёт много времени. Чувствуете решение? Правильно - работать с файлом в памяти, насколько это возможно. По крайней мере, не писать каждый заголовок отдельно, а сформировать в памяти нужную последовательность, а потом записать целиком. В идеале - работать с памятью, сбрасывая на диск только для исключения потери данных. Конечно, у вас база данных, т.е., вероятно, с одним файлом могут работать разные потребители. Что ж - определитесь, какие операции можно делать в памяти, и делайте только их. Прошу прощения, если залез в дебри - вы спрашивали несколько о другом - но надеюсь, мои рекомендации вам всё же помогут.
Rel Нужно учитывать особенности файловой системы, в данном случае (видимо) NTFS: см. в мсдн SetFileValidData и пояснения в двух словах, как работает SetEndOfFile Т.е. в твоем случае она отрабатывает быстро, поскольку на диск ничего не пишется и лишь изменяется значение File Size в атрибутах файла, при этом Allocation Size и Valid Data Length остаются прежними. Затем, когда ты пишешь только заголовки блоков с пропусками, ты не только ничего не выигрываешь якобы за счет того, что "данных пишется меньше (16 байт заголовка против 512 байт данных заголовка)", но наоборот, проигрываешь, т.к. ФС из соображений безопасности производит запись нулей в пропущенные куски и видимо тратит на все это "соображалово" значительно больше времени, чем если бы ты сам производил запись последовательно без пропусков Резюме: либо пиши все последовательно заголовок+данные (возможно вообще без SetEndOfFile), либо попробуй заюзать SetFileValidData (на XP и выше)
Rel Я бы предложил вам писать все одним блоком (за один вызов WriteFile). Т.е. - подготовить в памяти кусок данных: <блок n+1>...<блок n+m><конец файла>. - Увеличиваем размер файла на размер блока (SetFilePointer+SetEndOfFile) - устанавливаем File Pointer на конец блока n (SetFilePointer) - пишем кусок данных <блок n+1>...<блок n+m><конец файла> одним вызовом WriteFile Т.к. WriteFile - синхронная операция (диспетчер ввода-вывода не возвращат управление, пока не получит подтверждение от драйвера об окончании записи), то так будет гораздо быстрее. Да и с точки зрения целостности данных - одна тразакция лучше.
спасибо вам всем за советы! буду пробовать... хех... почему когда я о чем то на форуме спрашиваю, обязательно находится человек, который подумает о какой-нить гадости?))))