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 value of 16 (this is the absolute maximum)
- maxjournalsectors - 1, where maxjournalsectors is the argument of the fd.formatj method
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 |
|
FRT * 2 = 2 |
|
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.
- "FRT" means "one sector from the file records table." File records are changed when files are created, renamed, or deleted. They are also changed when the file size changes, or when your application sets new file attributes.
- "FAT" — "one sector from the file allocation table." File allocation sectors change when files are created and when file sectors are allocated or released in accordance with changing file sizes.
- "DATA" — "one sector from the data sectors area of the disk." Data sectors hold actual file data. They change when you write new data to files.
- "FRT * 2" and "FAT * 2" are caused by sector leveling: changing one FAT or FRT sector actually means changing two sectors.
- "DATA * 2" means that two data sectors can change when you write some data to the disk. This is because a portion of this data may reside in one data sector and the rest in another data sector.
- "X" parameter represents the number of active FAT sectors that can potentially be affected by invoking the corresponding method.
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)
fd.open("FILE1")
while fd.filesize>0
fd.transactionstart
fd.cutfromtop(i)
fd.transactioncommit
wend
fd.transactionstart
fd.delete("FILE1")
fd.transactioncommit
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.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
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.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