Understanding Transaction Capacity

Discussed in this topic: fd.transactioncapacityremaining.

The fd.transactioncapacityremaining read-only property can tell you how many changed sectors the transaction journal can still accommodate. The initial value of fd.transactioncapacityremaining (just after fd.transactionstart) depends on two factors, whichever is smaller:

The maxjournalsectors argument allocates the journal area of the flash disk. In this journal area, one sector is always needed for internal housekeeping, while other sectors cache the data sectors changed during the transaction. Therefore, if you want to achieve the maximum journal capacity (16), the journal must have at least 17 sectors in it. It is very important to use the maximum transaction memory capacity. The value of 16 is not random — it guarantees that you will always be able, within a single transaction, to change the data in two different files.

In practice, set a much higher journal size. This won't increase transaction memory, but it will prolong the life of the flash IC. Values in the 50-100 range are recommended.

A 14 — PL_FD_STATUS_TRANSACTION_CAPACITY_EXCEEDED error will be generated if transaction capacity is exceeded by performing too many disk write operations within a single transaction. The disk will be dismounted (but not damaged) and all changes to the disk made within this failed transaction will be forgotten.

Disk Operations and the Number of Sectors They May Affect

So how many sectors may be changed during various disk operations? The table below provides the worst-case numbers.

Fd. object's method that changes disk data

Maximum number of journal entries used


FRT * 2 + FAT * 2 + DATA = 5

fd.rename, fd.setattributes

FRT * 2 = 2

fd.delete, fd.setfilesize, fd.cutfromtop*

FRT * 2 + FAT * X * 2 = ?


FRT * 2 + FAT * 2 * 2 + DATA * 2 = 8

* Executing these methods can potentially overflow the transaction journal.

And now, the explanation for the table data. It is based on the material from Disk Area Allocation Details.

Here is how to calculate the X parameter:

Suppose the flash disk capacity (fd.capacity) is 1,000 sectors. The FAT, then, must hold 1,000 entries. Each FAT sector can hold 128 entries, so there will be 8 active FAT sectors (X = 8). Do not confuse this with the total number of sectors in the FAT area — it is at least twice this amount (because of sector leveling measures). The value "8" here represents the number of FAT sectors that are needed at any given time.

The fd.delete, fd.setfilesize, and fd.cutfromtop methods have one thing in common: they can potentially cut a huge file (occupying the entire disk) to zero. In the process, X FAT sectors will be altered!

Therefore, for a disk with fd.capacity = 1000, executing these methods can potentially change 2 + 8 * 2 = 18 sectors. This is above the maximum journal capacity, which is 16! So, how do you avoid the 14 — PL_FD_STATUS_TRANSACTION_CAPACITY_EXCEEDED error and still use transactions?

The answer is: do it in stages. The following example deletes a very large file in a "safe" manner:

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)
while fd.filesize>0

Not a Direct Sum Total

The worst-case number of sectors that may be changed during a transaction is not the sum total of maximum numbers for each fd. object method. In the example below, the maximum number of changed sectors is 9, not 10.

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

In this example, the worst-case number is 10, because we are working with two different files and their FRT records could be in different FRT sectors:

fd.setdata("write some data to a file") 'up to 8 sectors changed for file #0
fd.setattributes("ABC") '2 FRT sectors changed for file #1 
fd.transactioncommit 'therefore, the total is up to 10

Understanding Transaction Capacity

Disk Operations and the Number of Sectors They May Affect

Not a Direct Sum Total