The MainObjectBlock::Get function from quantum\block.cpp Figure block.18 codelist/block.18 The Set function Figure block.19 sets the value of an element of the main object array in the
Trang 1you can see, this function calls the corresponding function in the QuantumFile class to do the actual work
The FreeSpaceBlock::MakeLeafBlockPtr function (from quantum\block.cpp) (Figure block.16)
codelist/block.16
The MainObjectBlockPtr::MainObjectBlock class
The interface for MainObjectBlock is shown in Figure blocki.06
The interface for the MainObjectBlock class (from quantum\blocki.h) (Figure blocki.06)
codelist/blocki.06
As you can see, this interface is exactly the same as the one for
FreeSpaceArrayPtr::FreeSpaceArray, except that the
MakeLeafBlockPtr function is not included and the types used by the Get and Set functions are different, as is necessary for their proper functioning Because the default and normal constructors are exactly the same as those in the previous class, I'm not going to waste space reproducing them here, so let's move right along to the Get and Set functions
The Get function (Figure block.18) returns an element of the main object array in the block, using the m_MainObjectData union member
The MainObjectBlock::Get function (from quantum\block.cpp) (Figure
block.18)
codelist/block.18
The Set function (Figure block.19) sets the value of an element of the main object array in the block, also using the m_MainObjectData union member
The MainObjectBlock::Set function (from quantum\block.cpp) (Figure block.19)
codelist/block.19
Trang 2The QuantumBlock class
The interface for QuantumBlock is shown in Figure blocki.07 This is a more interesting class than the previous few we've discussed; it has a number of fairly complicated functions that we will need to go over in detail Probably the best place to start is with the AddItem function, because that is the function that adds each item to a quantum
The interface for the QuantumBlock class (from quantum\blocki.h) (Figure blocki.07)
codelist/blocki.07
The QuantumBlock::AddItem Function
Since there are actually two versions of this function, let's start with the simpler one, which takes a ModifiableElement (i.e., String) first argument The code for this function is shown in Figure block.20
One overloaded version of the QuantumBlock::AddItem function (from
quantum\block.cpp) (Figure block.20)
codelist/block.20
As you can see, this function retrieves the size and data address from its
ModifiableElement argument and then calls the other overloaded AddItem function, returning the result of that function to its caller So let's continue by looking at the other AddItem function, whose code is shown in Figure block.21
The other overloaded version of the QuantumBlock::AddItem function (from quantum\block.cpp) (Figure block.21)
codelist/block.21
This starts by setting the modified flag for its block; because we are going to
modify the block, we want to make sure that the block is written back to disk before the buffer is reused Then we call a global function called
FindUnusedItem to locate an item index entry that we can use for our new item.40 Then we call CalculateFreeSpace to figure out how much space is available in this block This is actually a safety measure, as the calling function is responsible for making sure that this block has enough free space before
attempting to add an item to the block But I'd rather be safe than sorry, so I check
Trang 3whether the free space is insufficient; if not, this is an error, which is trapped by the assert that immediately follows
However, let's assume that we do have sufficient room to store the new item In that case, we continue by checking whether the item number that was returned by FindUnusedItem is greater than or equal to 0 If so, we are going to reuse an item that has been previously used, so we set its type and index value to the new values supplied as arguments to the AddItem function
We've referred to the ItemIndex data type a few times in the past, but haven't really looked at what it consists of I think this would be a good time to do so, so let's take a look at its definition, which is shown in Figure blocki.08
The definition of the ItemIndex struct (from quantum\blocki.h) (Figure
blocki.08)
codelist/blocki.08
This is a fairly simple data type, consisting of an index entry (which represents the element number of this item in the array of which it is an element), the offset of the beginning of the data for the element from the end of the block, and a type
indicator that specifies the type of the element While the purpose of the offset member variable should be fairly obvious, the purpose of the other two member variables may not be The purpose of the type indicator is consistency checking; if we're trying to access a little pointer array, we can use this type indicator to make sure that we are getting what we expect In a similar vein, the purpose of the index entry is to provide information needed by a program that will recover data from a quantum file that has become corrupted
Now let's continue with our analysis of the AddItem function (Figure block.21), where we have just updated the type and index of the item index entry that we are reusing to the new values supplied as arguments to this function Next, we extract the offset field from that item index entry and call GetItemCount to find out how many items are in the index Now we have to calculate the parameters needed
to shift the data already in the quantum so that we have room for our new item The offset of the last item is equal to the distance in bytes from the beginning of that item to the first byte after the end of the quantum Therefore, the address of the beginning of the last item in the quantum, DataFrom, can be calculated as the address of the beginning of the buffer in which the quantum resides, plus the size
of a quantum, minus the offset of the last item in the quantum The byte at that address, and all those after it up to the starting address for the new item's data,
Trang 4must be moved down in memory by enough to leave room for the new data.41
Therefore, the new address of that first byte of the last item's data, DataTo, will
be its old address minus p_ElementSize We want to move all of the items that precede our new item in memory, which means those that have higher item
numbers; therefore, the number of bytes we want to move, DataLength, is equal
to the distance from the beginning of the last item to the beginning of the area where we will store our new item Now that we have calculated these parameters,
we can call the global BlockMove function to perform the transfer
Now we have moved the existing data, but the index still refers to the old locations
of the data, so we have to call the global AdjustOffset function to adjust the elements of the item index that refer to data that has been moved Once we have adjusted the item index, we calculate the address where the new data will be stored and call BlockMove again, this time to copy the new data to the correct place in the block Finally, we calculate the return value from this function, which is the item number of the item we have entered, as one more than the index of the item entry we reused; this adjustment is needed because item numbers start at 1 rather than 0
I think an example might be very helpful here Suppose that we want to insert a new field with index number 6 to store the company name ("Chrysalis") in the following quantum, reusing the currently unused fourth item (see Figure insert1)
Item index and data before item insertion (Figure insert1)
+-
| Item # Offset Type Index
| + -+
| 1 | 5 -+ VARSTRING 4 |
Item | 2 | 17 +| VARSTRING 0 |
Index | 3 | +-19 || VARSTRING 3 |
| 4 | | 19 || UNUSED 0 |
| 5 | ++-31 || VARSTRING 1 |
| 6 |+++-38 || VARSTRING 2 |
| ++++ ++ -+
+- ||| |+ -+
||| + -+ |
||+ -+ | |
+- |+ -+ | | |
| + + -+ -+-+ -+ +
Quantum | | BaldwinP.O.Box 0335NYSteve Heller11510|
Trang 5Data | + -+
+-
+-
Quantum | 333333333222222222211111111110000000000
Offset | 876543210987654321098765432109876543210
+-
+-
| 666666666666666666666666666666666666666
| 111111111111111111111111111111111111111
Address | 000011111111112222222222333333333344444
| 678901234567890123456789012345678901234
+-
To do this, we have to move items 5 and 6 toward the beginning of the quantum by 9 characters, which is the length of the new item Assuming that the address of the beginning of the buffer holding the quantum is 4096 and BlockSize is 2048, the address of the beginning of the last item is 4096+2048-38, or 6106, which is the value of DataFrom The value of DataTo is calculated from DataFrom by subtracting the length of the new item, or 9, resulting in 6097 The value of DataLength is the amount of data to move; we have to move everything from the last item up to but not including the place where we are going to put the new data We could add up the lengths of all of the items from the last item to the one before which we will insert our new data, but it is easier simply to subtract the offset of that item from the offset of the last item, which produces the same result: 38 - 19, or 19 bytes to be moved After the move, the quantum looks like Figure insert2 Item index and data after move (Figure insert2) +-
| Item # Offset Type Index
| + -+
| 1 | 5 -+ VARSTRING 4 |
Item | 2 | 17 +| VARSTRING 0 |
Index | 3 | +-19 || VARSTRING 3 |
| 4 | | 19 || UNUSED 0 |
| 5 | ++-31 || VARSTRING 1 |
| 6 |+++-38 || VARSTRING 2 |
| ++++ ++ -+
+- ||| |+ -+
Trang 6||| + -+ |
||+ -+ | |
+- |+ -+ | | |
| + -+ | | | |
| + -+ -+ -+-+ -+ +
Quantum | | BaldwinP.O.Box 0335?????????NYSteve Heller11510|
Data | + -+