Skip to main content

     
  TPF : Library : TPF Newsletters
Products > Software > Host Transaction Processing > TPF > Library > Newsletters >
Newsletter Image

FAQs about Collections

Daniel Jacobs, IBM TPF Development

Newsletter Image Hi! This is Ree Porter back on assignment with the TPF collection support (TPFCS) team. It has been a while since my last article in the second quarter of 1999, but now I'm back by popular demand! Once again, I recently acted as a liaison at a meeting between TPF customers and the TPF lab, seeing what kinds of questions the customers had about TPFCS. Now I'm here to report the answers to all of you.

Note: Just like last time, the names in this article have been changed to protect the innocent. Any correlation to actual names is strictly coincidental.

Date:

Monday, November 6
Attendees: Will Notfly (Database administrator for Wingless Airlines)
Rich Mann (System Administrator at Knight Trader Securities)
Bill Meelater (Application Programmer at Tumuch Credit Corporation)
Albert (TPFCS programmer)
Dan (TPFCS programmer)
John (TPFCS programmer)
Glenn (TPFCS all-knowing individual)

C (comment). Ree: It's great to see all of you again! I've heard that there have been a couple of questions about TPFCS recoup, so why don't we start with that. Who wants to begin?

Q (question). Will: I will. First of all, I recently displayed the contents of file system #INODE record ordinal 0 and saw a persistent identifier (PID) in there. When I displayed the contents of the file address in the PID, I noticed that it was a Wingless record ID and not the expected TPFCS record ID of FC16. However, recoup did not report an error with this record. This leads me to believe that the address was not chain chased. Is there something special that I have to do?

A (answer). Dan: That is an excellent observation. In general, unless you have your own user-created data stores, there isn't anything special that you need to do for recoup to work with TPFCS and TPF data stores . . . except for one important thing. You have to make sure that the BKD7 descriptor is loaded to your system. The BKD7 descriptor tells recoup that within the file system #INODE (x'FC2A') records there are embedded PIDs to chase. Without this descriptor, the pools used by these embedded collections will not be protected and could be made available for reuse, which probably explains how your record ID got corrupted in the first place.

C. Will: That makes sense. I will have to double-check that.

Q. Rich: Does the TPFCS descriptor (BKD7) have to be in a specific ordinal slot on the BKD tape, such as at the beginning or the end, or can it be anywhere on the BKD tape?

A. Albert: First of all, to clarify some terminology, the BKD7 descriptor is not the TPFCS descriptor. There can be many TPFCS descriptors in a system. Actually, BKD7 is really a file system descriptor because it describes the x'FC2A' fixed file records that the file system uses.

C. Rich: OK, but getting back to the question . . .

A. Albert: Oh, right. To answer your question, no, the BKD7 descriptor does not have to be in any particular ordinal slot. Basically, prior to PUT 13, TPFCS recoup would run first at the beginning of phase 1. As part of its processing, it creates a TPFCS heap area that is used for keypointing purposes. This area is still available after TPFCS recoup is completed, and remains available until the end of phase 1. Therefore, as long as this area is still available, the BKD7 descriptor can run. This processing changes a bit with the recoup being shipped on PUT 13, but that's a whole different topic.

A. John: A personal preference would be to have this descriptor run toward the beginning of TPF recoup, just to logically group the processing of TPFCS records.

Q. Rich: How does the recoup code know it's a TPFCS descriptor?

A. Dan: For any traditional TPF file that contains embedded references to TPFCS PIDs, such as with BKD7, there is a PID=YES parameter on the INDEX macro that indicates this. When TPF recoup encounters this, it takes the PID and passes it to TPFCS recoup for processing.

A. Albert: If you were to have traditional file addresses embedded within TPFCS collections, a descriptor must be coded for the record IDs that are embedded. In this case, the GROUP macro contains an IND=C and USE=TPFCS option that indicates that the descriptor will not be chased by TPF recoup, but instead will be handled by TPFCS recoup. More information on this is available in the TPFCS chapter in TPF Database Reference.

Q. Dusty: OK, so if I understand this now, the BKD7 descriptor only chases the fixed file INODE records. Is there a descriptor that chases the IBMM4 (ordinals 121 & 148) fixed files that we might be missing?

A. John: No. BKD7 is specifically used to chain chase INODEs that are used by the TPF file system, as you described. Although there are embedded PIDs within the IBMM4 ordinals, these are actually handled automatically by TPFCS recoup processing at the beginning of phase 1, so nothing additional needs to be loaded to the system. TPFCS recoup will automatically recoup any collections that it creates. Users are responsible for creating recoup indexes to describe the location of any collections that they create. Details on this procedure are also available in the TPFCS chapter of TPF Database Reference.

C. Rich: TPF Database Reference sounds like a very handy document!

Q. Rich: How do I create and maintain these recoup indexes?

A. John: That's easy! You have two choices. You can either write an application for this purpose using the TO2_ APIs, such as TO2_createRecoupIndex, TO2_addRecoupIndexEntry, and TO2_associateRecoupIndexWithPID, or you can use the ZBROW RECOUP functional message that is provided with PUT 12.

Q. Will: Just to double-check, are there any special TPFCS recoup considerations regarding the Internet daemon server's usage of long-term pool?

A. Glenn: No, the Internet daemon uses the file system, which, like we have said, is covered by the BKD7 descriptor. MQSeries definitions are automatically recouped, and MATIP definitions are supposed to be recouped, but you will actually need APAR PJ27688 applied for this to happen.

Q. Rich: Is a TPFCS recoup index only required for collections that have either embedded PIDs or file addresses? If a collection does not contain embedded PIDs or file addresses, is the collection automatically protected?

A. Dan: Yes, you only need to associate a recoup index with a collection when that collection contains embedded PIDs or file addresses. Assuming that something is pointing to a collection, the pool files that the collections consist of will be recouped regardless of whether or not that collection contains embedded references. The recoup index for a collection is only required if the collection will contain embedded file addresses or PIDs that have to be recouped. The recoup index tells TPFCS how to find the embedded pointers to other collections. It is just like the normal TPF recoup descriptors in that you would only create the indexes if the pointed to collections could only be recouped from this collection. You wouldn't want the collections to be recouped multiple times because it would slow down the recoup run, but at the same time you want to make sure that they are recouped at least once.

A. John: TPF will automatically recoup all system collections that TPFCS creates on its own, such as the application and system dictionaries, the browser dictionary, an so on. All other collections must be referenced by a collection that has a recoup index associated with it so that recoup knows how to find the referenced collections.

Q. Rich: My collections do not have embedded PIDs in them. However, I store the PIDs for my collections in the data store user dictonary (DS dict). When I delete the collections, I also delete the entry in the DS dict containing the associated PID. Am I right that these PIDs do not have to have recoup indexes associated with them?

A. Albert: Yes, but if you are storing PIDs in the DS dict (that is, the DS_USER_DICT collection), you do have to create and assign a recoup index to the DS dict collection. You can decide if you want the DS dict to be homogeneous or heterogeneous. The obvious advantage to making it homogeneous (that is, each element has the same format) is that you can have a single entry in the recoup index associated with the DS dict, and you don't have to change the recoup index when you add collections to, or remove collections from, the DS dict.

Q. Will: If we issue the ZOODB INIT functional message, does this initialize both the file system and TPFCS?

A. Albert: Yes. This functional message must be issued from CRAS state or above on the basic subsystem (BSS), and it will do several things. First, it will initialize TPFCS by creating the TPFDB data store on the BSS. It will then initialize the file system on the BSS by creating the IFSXBSS data store. Finally, it will initialize the file system on any other subsystem that is also in CRAS state or above by creating a distinct IFSX data store for that subsystem.

A. Dan: Don't forget that you can later initialize the file system on subsystems that weren't initialized when TPFCS was initialized by using the ZFINT ON functional message.

C. Ree: Wow, that is a lot of good information about recoup; and don't forget that there is a new recoup deliverable that has shipped on PUT 13 that you can read about elsewhere in the TPF Systems Technical Newsletter.

C. Dan: Wow, it's almost as if I willed you to say that. Thanks!

C. Ree: Sure! OK, what is the next topic going to be?

Q. Rich: We have a couple of performance issues. We've done a few quick tests to see what the performance of TPFCS would be like. Our initial results show that TPFCS performance seems to be about 15_20 times worse than the TPF Database Facility (TPFDF). Is this to be expected or can the application be optimized with some advice?

A. Glenn: There are two major differences in performance between TPFDF and TPFCS. The first is that TPFCS uses commit scopes to process all database updates. On relatively small-scale systems, this causes every collection update to be delayed approximately 10 ms. The delay is because the update most likely does not completely fill a commit buffer, and commit processing waits that amount of time before filing out the partial buffer and allowing the ECB to continue.

Q. Will: So can anything be done about this?

A. Glenn: The main way around this problem is for the application to open its own outer commit scope around the updates. This causes all of the TPFCS commit scopes to be handled as nested commit scopes and to be rolled into the outer commit scope with no time delay. When the application issues it's commit, all of the TPFCS updates will be filed out at that time with, at most, a single 10-ms delay. The downside of this is that you probably don't have enough VFA resources to hold the complete set of updates. Therefore, you will have to break up the outer commit scope into smaller scopes. For example, you may have to open a commit scope, do 100 updates, commit the updates, and then reopen a new commit scope to do the next 100 updates. By doing this, you can cut out most of the time overhead involved.

Q Will: Hmm, that sounds promising. What is the other major performance difference between TPFDF and TPFCS?

A. Glenn: There is a path length increase in TPFCS that, depending on the functions, can be from a few percentage points to an order of magnitude. To cut down on path length overhead, the application should use a locking cursor when more than one operation is to be performed against a single collection. Because TPFCS doesn't know how the application is using a collection, TPFCS will always read the collection into malloc storage, process the request, and write the collection back to DASD unless the application has a cursor opened against the collection. If the application uses cursors, TPFCS holds on to the collection until the cursor is closed. This saves all the reading and writing of the collection's control structures between every API call. The downside is that in order to update the collection, a locking cursor is required and this will cause the collection to be locked for the entire time the cursor is opened.

Q. Bill: Hey, could you guys sketch this out in a sample program format?

A. Albert: Sure. OK, to get the best performance, the application loop might look something like this:

while (more To Process == TRUE)
{
/* start outer commit scope */
   tx_begin()

/* tell TPFCS to get a collection and hold on to it */
   TO2_createReadWriteCursor()

/* do 100 (could be more or less depending on resources needed)
   updates using APIs like TO2_atNewKeyPut */

/* delete the cursor & allow TPFCS to file out any updates still in memory */
  TO2_deleteCursor()

/* now commit all TPFCS updates to disk. */
   tx_commit()
}

C. Ree: Great! I'm glad I brought all of these colors!

Q. Rich: We also noticed that there are a significant amount of reads to the DASD surface from various TPFCS records, such as x'FC10', x'FC11', and x'FC16'. Could we set these record IDs as VFA-IMMED in a non-loosely coupled environment so that they are core resident?

A. Albert: Unfortunately, no. You cannot make them VFA candidates without causing database corruption unless you use VFA sync and make them VFA-SIMMED. The TPFCS record IDs should be set to either VFA-NO (which is the default setting), or to VFA-IMMED for uniprocessor support, or to VFA-SIMMED for loosely coupled support. They should never be set to VFA-IMMED or VFA-DLAY on loosely coupled systems.

Q. Will: I also have some questions concerning locking. I am creating a package that will dynamically create collections and store the PIDs for these collections in the data store dictionary (DS dict). I need to write a "nightly maintenance" program that will loop through the entire collection and delete all entries beyond a certain date. I noticed that there are only a limited number of TPFCS functions for the DS dict. Could I create a locking cursor for the DS dict and use the cursor functions to search the DS dict? If not, is there a way to do what I want to do (without of course building my own index file as a collection)?

A. Glenn: The easiest way is to use the locking cursor, as you described. The only problem with the locking cursor is that the collection will be locked for the duration of the scan. Another way of doing it would be to create a standard cursor on the collection and use it to locate the keys, and then do a TO2_removeKey on the key to be deleted. This would cause the collection to be locked only during the remove request itself as long as your application was not in a commit scope. If you are using your own commits, the collection would then remain locked from the first remove until your application did the final commit. The problem with this approach is that because the collection is not locked but is actually being processed using dirty reads, every remove will cause TO2 to reaccess the collection control information, update it, and then write it back out again. This could have an adverse affect on performance if performance is a concern for this operation.

C. Ree: So, to summarize, the locking cursor and a cursor remove request is the fastest but it has a lock duration problem, whereas the standard cursor using TO2_removeKey bypasses the lock duration problem but has a performance concern. It sounds like you will have to make the choice.

Q. Bill: I'm still a little confused about how collection locking works. Let's say we have a large array, and we start to update element 1000. If another application at the same time tries to update element 2000, what will happen?

A. Albert: In this case, the request by the second application will be queued until the first application has released its lock on the collection. This is done either by completing an atomic collection API, such as TO2_atPut(), or by deleting a locking cursor. At this point, the second application will lock the entire collection (not just element 2000) and process the update request.

Q. Will: I had a couple more database design questions. First, I was reading a little bit about temporary collections. These collections always remain in core, right?

A. Glenn: Well, actually, these collections will overflow to short-term pool if they become too large to fit in memory.

Q. Will: Secondly, are the elements in a collection all the same size, or can they be variable in length?

A. Dan: Another good question. The answer depends on the collection type. For arrays, logs, keyed logs, and BLOBs, the collection elements all have the same logical size, which is specified when the collection is created. In reality, the application can physically create elements that are smaller than this common, maximum size. For all other collection types, the elements can be different sizes within the same collection, and the maximum length of an element within a particular collection is specified when the collection is created.

C. Bill: Would you all mind if I asked a couple of application questions?

C. Ree: Go right ahead!

Q. Bill: Thanks. If we have a key bag and we do a TO2_locate using a particular key value, will TO2_next return the next element with the same key value?

A. Dan: No. Key bags and key sets do not have a defined next or previous element, so issuing a TO2_next in your situation could return any element, including one with a different key value. If you were to use a key sorted bag or key sorted set, TO2_next would return another element with the same key.

Q. Bill: Is there any sample code that TPFCS can provide?

A. Albert: Why does that question sound familiar? Sure, we have sample code that we provide on request. You should contact your IBM TPF representative.

Q. Rich: Before we end this, I had a couple of database maintenance questions. Is there a way for me to delete a data store?

A. Glenn: It's funny you should ask that. As we sit here during this question and answer session, there is no supported interface for deleting a data store. There is a way to do it "under the covers", but you should contact the TPF Lab for more information. In addition, at this very moment, there is a programmer back in Poughkeepsie, NY who is looking into this very issue and may be providing an interface before too long (wink, wink).

Q. Rich: Is it safe to assume all updates to a FARF record in the TPFCS database will have a hold on the record before it is filed.

A. John: No, TPFCS does not hold each record when updating. Currently the control record (FC16) whose address is in the PID is the record held. This hold pattern might change over time to allow concurrent updates.

Q. Rich: I'm getting certain errors out of TPFCS. How would I go about debugging the problem?

A. Dan: As much as we would love to explain everything to you here, there is just too much to understand in one sitting. There is no fixed set of instructions for debugging a TPFCS problem; it really varies from problem to problem. For starters though, you may want to consider using the ZBROW DISPLAY functional message to collect as much information as you can about particular collections. How about we come back next time and discuss this in more detail?

C. Rich: That sounds good.

Q. Ree: This has been very helpful. Are any of you planning on giving any TPFCS classes?

A. Dan: Actually, a class is being put together and might even be available by the time these interviews are published. Contact your IBM service representative for more information.

C. Ree: Well then, this concludes our second investigative report into customer questions about TPFCS. I'm sure there will be more questions to report on, so keep an eye out for my return before too long!

Fourth Quarter 2000 - Table of Contents