Ёмкость транзакции
В этом разделе рассматривается: fd.transactioncapacityremaining.
Свойство fd.transactioncapacityremaining (только чтение) показывает, сколько ещё изменённых секторов поместится в журнал транзакций. Начальное значение fd.transactioncapacityremaining (сразу после fd.transactionstart) определяется меньшим из двух значений:
- 16 (абсолютный максимум)
- maxjournalsectors - 1, где maxjournalsectors - аргумент метода fd.formatj
Аргумент maxjournalsectors задаёт размер области журнала на флеш-диске. В этой области один сектор всегда занят служебными данными, а остальные кэшируют секторы данных, изменённые в ходе транзакции. Поэтому для максимальной ёмкости журнала (16) в нём должно быть не менее 17 секторов. Очень важно использовать максимальную ёмкость памяти транзакций. Значение 16 выбрано не случайно - оно гарантирует, что в одной транзакции всегда можно изменить данные в двух разных файлах.
На практике задавайте гораздо больший размер журнала. Память транзакций от этого не увеличится, зато продлится срок службы флеш-микросхемы. Рекомендуются значения в диапазоне 50-100.
Если превысить ёмкость транзакции, выполнив в одной транзакции слишком много операций записи на диск, возникает ошибка 14 - PL_FD_STATUS_TRANSACTION_CAPACITY_EXCEEDED. Диск будет размонтирован (но не повреждён), а все изменения, сделанные на диске в этой неудавшейся транзакции, будут отброшены.
Дисковые операции и число секторов, которые они могут затронуть
Сколько же секторов может измениться при разных дисковых операциях? В таблице ниже приведены значения для худшего случая.
| Метод объекта fd, изменяющий данные на диске | Максимальное число используемых записей журнала |
| fd.create | FRT * 2 + FAT * 2 + DATA = 5 |
| fd.rename, fd.setattributes | FRT * 2 = 2 |
| fd.delete, fd.setfilesize, fd.cutfromtop* | FRT * 2 + FAT * X * 2 = ? |
| fd.setdata | FRT * 2 + FAT * 2 * 2 + DATA * 2 = 8 |
* Выполнение этих методов может переполнить журнал транзакций.
Теперь объясним данные таблицы. Объяснение опирается на материал раздела Распределение области диска.
- «FRT» означает «один сектор из таблицы записей о файлах». Записи о файлах меняются при создании, переименовании и удалении файлов. Они меняются и при изменении размера файла, и когда приложение задаёт новые атрибуты файла.
- «FAT» - «один сектор из таблицы размещения файлов». Секторы таблицы размещения меняются при создании файлов, а также при выделении и освобождении секторов файлов по мере изменения их размеров.
- «DATA» - «один сектор из области секторов данных диска». В секторах данных хранится содержимое файлов. Они меняются, когда вы записываете в файлы новые данные.
- «FRT * 2» и «FAT * 2» объясняются выравниванием износа секторов: изменение одного сектора FAT или FRT фактически означает изменение двух секторов.
- «DATA * 2» означает, что при записи данных на диск могут измениться два сектора данных: часть данных может оказаться в одном секторе, а остаток - в другом.
- Параметр «X» - это число активных секторов FAT, которые может затронуть вызов соответствующего метода.
Вот как рассчитать параметр X:
Допустим, ёмкость флеш-диска (fd.capacity) составляет 1000 секторов. Тогда FAT должна вмещать 1000 записей. В каждый сектор FAT помещается 128 записей, значит, активных секторов FAT будет 8 (X = 8). Не путайте это с общим числом секторов в области FAT - оно не меньше чем вдвое больше (из-за мер по выравниванию износа секторов). Значение «8» - это число секторов FAT, которые нужны в любой момент времени.
Методы fd.delete, fd.setfilesize и fd.cutfromtop объединяет одно: каждый из них может усечь огромный файл (занимающий весь диск) до нуля. При этом будут изменены X секторов FAT!
Поэтому для диска с fd.capacity = 1000 выполнение этих методов может изменить 2 + 8 * 2 = 18 секторов. Это больше максимальной ёмкости журнала, равной 16! Как же избежать ошибки 14 - PL_FD_STATUS_TRANSACTION_CAPACITY_EXCEEDED и всё же использовать транзакции?
Ответ: делать это по этапам. Следующий пример «безопасно» удаляет очень большой файл:
dim i as byte
i=(fd.transactioncapacityremaining-1)/2 'this is how many FAT sectors we can change at once
i=i*128 'and this is how many data sectors we can cut from the file at once (one FAT sector holds 128 entries)
fd.open("FILE1")
while fd.filesize>0
fd.transactionstart
fd.cutfromtop(i)
fd.transactioncommit
wend
fd.transactionstart
fd.delete("FILE1")
fd.transactioncommit
Не простая сумма
Число секторов, которые могут измениться за транзакцию в худшем случае, не равно сумме максимальных значений для каждого метода объекта fd. В примере ниже максимальное число изменённых секторов равно 9, а не 10.
fd.transactionstart
fd.setdata("write some data to a file") 'up to 8 sectors changed, and this includes 2 change FRT sectors
fd.setattributes("ABC") 'FRT changes again, but for the same FRT record (this will use only 1 entry in the journal)
fd.transactioncommit 'therefore, the total is up to 9
В этом примере худший случай равен 10, потому что здесь работа идёт с двумя разными файлами, и их записи FRT могут находиться в разных секторах FRT:
fd.transactionstart
fd.finenum=0
fd.setdata("write some data to a file") 'up to 8 sectors changed for file #0
fd.filenum=1
fd.setattributes("ABC") '2 FRT sectors changed for file #1
fd.transactioncommit 'therefore, the total is up to 10