FAQs about Collections
Daniel Jacobs, IBM TPF Development
 |
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
|