MVS TOOLS AND TRICKS OF THE TRADE JULY 2007 Sam Golob MVS Systems Programmer P.O. Box 906 Tallman, New York 10982 Sam Golob is a Senior Systems Programmer. He also participates in library tours and book signings with his wife, author Courtney Taylor. Sam can be contacted at sbgolob@cbttape.org. Information about the CBT MVS Tapes can be found on the web, at http://www.cbttape.org. THE STRUCTURE OF THE BROADCAST DATASET - PART 2 Last month, we talked about the basic structure, and some of the general details, of the TSO Broadcast Dataset, which used to exclusively be called SYS1.BRODCAST. The Broadcast Dataset is part of the "messaging facility" which belongs to TSO under MVS, and it has been around (as SYS1.BRODCAST) since the MVT times, long before MVS was given its name. As we mentioned last month, messages are sent under TSO using the TSO SEND command. And if the messages were not received immediately by the intended receiving Userid, they are displayed for that Userid by the LISTBC TSO command when it is issued, being deleted from the Broadcast Dataset afterward. Later versions of TSO/E allow for individual TSO Userlogs to be created, to store these messages, provided that Userlogs are specified in the active IKJTSOxx member of Parmlib, and that the individual user actually creates his or her Userlog the first time. A TSO user can issue the LISTBC command at any time, or it is automatically issued on behalf of every user at LOGON time. LISTBC, besides displaying the Global Notification messages that are in the Broadcast Dataset for everyone to see, also displays each user's stored Userid Messages. But the stored Userid messages, particular for that user only, are then deleted by LISTBC. Global Notification messages, which are displayed by LISTBC for every TSO user, remain on the Broadcast Dataset until they are changed by a SEND subcommand of the OPER TSO command. Actually, when LISTBC displays the Global Notification messages, LISTBC does not access the Broadcast Dataset itself, but it reads an incore copy of the Notices messages. This is so that if a few hundred TSO users LOGON, say at 9:00 in the morning, all at once, there won't be an enqueue bottleneck on the Broadcast Dataset. What event will trigger a change to the incore copy of the Global Notices? It is the setting of a bit, the TSVTCNVU bit in the TSO Vector Table which is chained off the CVT, and mapped by the IKJTSVT macro that is in SYS1.MACLIB. Issuing an OPER SEND command, will both set this bit, and will read this bit, to trigger a rereading of the Broadcast Dataset, to update the Incore Global Notices Table. After TSO/E Release 3, which came out with z/OS 1.3, the LISTBC command itself, will read the TSVTCNVU bit, and it will update the Incore Table and turn the bit off. Therefore, after TSO/E Release 3, if you set this bit on, the first person who logs on, and in the process, invokes the LISTBC command, will cause the update of the Incore Global Notices Table to take place. THE PIECES OF THE BROADCAST DATASET Now it's time to get to the nitty gritty details of the Broadcast Dataset, that I promised to talk about last time. Physically, the Broadcast Dataset is a keyed UNBLOCKED dataset (RECFM=F, KEYLEN=1) with 129 data bytes, so the LRECL=129. The type of record in the Broadcast Dataset is described by the value in the one-byte key. See Figure 1, which describes all the possible record types in the Broadcast Dataset, and which also shows the macros in SYS1.MACLIB which document the format of each type of record. I use the free REVIEW TSO command to look at a Broadcast Dataset, because REVIEW will show all the key and data bytes correctly. ISPF Browse will drop the last data byte off, which causes you to "not see" very valuable data at the end of the record. You can get the REVIEW program from File 134 (source) and File 135 (load modules) on the CBT Tape website. To get the website's URL, do a www.google.com search for "CBT Tape". There are three "logical pieces" of the Broadcast Dataset, which can conceptually be pictured as being completely separate from each other. These are: the Global Notification Messages, the Userids, and the User Messages. Each of these pieces must be considered separately, although the User Messages have to be attached to Userids. So therefore the Userids need to come first, before any User Messages can be created and stored. A new Broadcast Dataset is formatted (after its space is allocated) by IBM's SYNC subcommand of the ACCOUNT TSO command. The SYNC subcommand creates an empty Broadcast Dataset, but it fills the Userid section with TSO Userids from both the SYS1.UADS dataset, and the RACF Database. Of course, the SYNC subcommand, created by IBM, will not attempt to read the databases of the other MVS security products, such as ACF2 and Top Secret, which are proprietary CA products. So installations which have ACF2 or Top Secret have to do their own Userid synchronization procedures which read the respective security databases and extract TSO-connected Userid names. Once the Userid names are extracted, however, they are loaded into the Broadcast Dataset by the respective security products in a completely standard way. We will now talk about the three separate logical components of the Broadcast Dataset, starting with the Userids, and then discussing the User Messages (which are related to the Userids) and finally the Global Notices Message system. THE USERID DESCRIPTORS You can't get anywhere in the Broadcast Dataset without reading the Header Record first, indicated by X'04' in its key byte. The Header Record (always Relative Record Address X'000000') points to the three-byte Relative Record address of the first Userid Record, and it is from there, that we start our search to see whether a particular Userid is defined in the Broadcast Dataset. To be exact, the pointer to the first Userid Record is described by field R1USPTR of macro IKJZT301 in SYS1.MACLIB. Once you've gotten to the first Userid record and you READ it, you'll notice that the last three bytes of it point to the next Userid record, and so forth, until we come to the last Userid record, which points to X'000000' which means to nowhere. Once we come to the last Userid record, it is considered that we have read all of them. A Userid record in the Broadcast Dataset is indicated by an X'01' in the one-byte key field. Each Userid record has room for nine Userid descriptors, each of which defines one Userid to the Broadcast Dataset. The reason for 9, is because each Userid descriptor takes up 13 bytes--7 bytes for the Userid itself, and 6 bytes for two 3-byte RBA (relative record) locations. Nine 13-byte descriptors will fit into the 125 usable bytes of a Userid record. The 6 extra bytes which contain the two 3-byte RBA's, are the Relative Record locations of the first User Message and the last User Message attached to this Userid. In between, all the User messages are chained to each other, by an RBA number in the last 3 bytes of each message, which points to the location of the next message. In other words, the first message for a Userid is pointed to by the first RBA in the Userid record. After that, this Userid's messages are all chained to each other. And the last User Message contains an X'000000' in its last three bytes, showing that it is the last message attached to this Userid. Redundantly, the RBA location of this last User message is repeated in the second RBA of the Userid descriptor. Any of you who is Mathematically inclined (and most of you who are not) can see that to determine the location of the last message attached to a Userid, you need only follow the chain through all the messages, starting from the RBA of the first User message attached to this id. Why do we need the RBA of the last message, to be also stored in the second RBA location in the Userid descriptor? The answer is for efficiency. It is for the SEND command. The RBA of the last message is provided directly, so that when you SEND a new message to a Userid, you won't have to chain through all the existing messages first, to see where the last message is. There might be thousands of other messages already there for a particular Userid, and this situation happens often. So you want to find the last message's location easily. Back in the old MVT days, a Userid record actually contained only 10 bytes instead of 13, and this was because only the starting RBA for the first User Message was provided. But in MVS, the RBA of the last message was inserted into the Userid descriptor for efficiency. Since there are 125 usable bytes in an actual Userid Record, nine 13-byte Userid descriptors can fit in. Back in the old MVT days, when the Userid descriptors were only 10 bytes long, 12 Userids could fit into a Userid record. So the MVS Broadcast Dataset format for Userid descriptors has always been the same, but if you go back to an MVT system, which you can run nowadays under Hercules on a PC, there were 12 Userid descriptors in a Userid Record instead of 9. USERID MESSAGES THEMSELVES, AND EMPTY RECORDS A User Message record in the Broadcast Dataset is described by a X'03' in the key field. The first data byte, after the key byte, contains the binary length of the actual message, and the message itself follows afterwards, starting from byte two of the data in the record. This is very simple to understand. A User Message can therefore be up to 125 bytes long. 3-bytes at the end are necessary to chain to the next message, and the actual message starts from byte 2 of the data. So 125 bytes are left. An empty record, described by an X'FF' in the key field, is a bit more complicated. Empty records are usually used to contain a User Message later, but an empty record can also (potentially) be converted into an extra Userid Record, if you want to define more Userids to the Broadcast Dataset, and there's no room for them in the existing Userid Records that are already there. So then, an X'FF' record gets converted into an X'01' (Userid) record instead of an X'03' (User Message) record. There's something very particular about the X'FF' records. If you don't understand this, you can cause a great deal of trouble. Here's the deal. In order for an X'FF' record to be valid, it has to contain the binary value of its record location on the track, the "R" of the CCHHR or TTR value describing the location of the record, in the first data byte location of the record itself. In other words, you can't move an X'FF' record to a different location of the track. That is why IBM says that you can't use conventional means, to copy a Broadcast Dataset from one device type (like a 3390) to another device type (like a 3380). It will come out, that the X'FF' records will have their first data bytes NOT pointing to their correct location on the track, since on a 3380 (for example), 53 Broadcast Dataset records will fit on a track, but on a 3390, only 50 records will fit on a track. So the "R" numbers on a 3380 will go from X'01' to X'35', but on a 3390, the "R" numbers will go only from X'01' to X'32'. And if the first data byte of an X'FF' record is wrong, the Broadcast Dataset is considered corrupted. It will definitely not work correctly. So any means of copying a Broadcast Dataset will have to take into account the absolute value of the track locations for all the X'FF' records. Sorry about that. I'll talk more about it next month. THE GLOBAL NOTIFICATION MESSAGING SYSTEM From the purely Broadcast Dataset point of view (excluding consideration of the Incore Notices Table), Global Notices are controlled by two types of records: the X'00' Global Notices Directory records which each contain 25 5-byte entries, and the X'02' Global Message records themselves, which contain the messages. The X'00' Directory records are described by the IKJZT302 macro in SYS1.MACLIB. Each 5-byte directory entry points to a sequentially numbered Notices Message record. The first two bytes in binary, tell you what the message number is, and the next 3 bytes provide the actual message's RBA location. A Notices Message (as described by its directory entry) is considered ACTIVE, if its high-order bit, X'80' of the first byte of the five, is OFF. Otherwise, if the X'80' bit of the directory entry is ON, the Notices message is considered INACTIVE, and whatever information is in it, will not be displayed. All the X'00' records are chained to each other, similarly to the way the Userid Records are chained to each other. The X'02' Notice records, which contain the actual Notice messages, are very simple. The first byte of the data portion, contains the length of the message. And the rest of the record contains the message itself. No indication is present in the Notices Message itself, as to whether that message is ACTIVE or not. It all depends on the X'80' byte in the 5-byte directory entry for that Notice Number, which points to that Notice. If the X'80' bit is OFF, then the corresponding Notice message is ACTIVE, otherwise that Notice message is INACTIVE, and it will not be displayed, no matter what data the X'02' record actually contains. This concludes our discussion of the Global Notices record system, for now. One more record, the X'05' or Free Search Record, needs to be described. This record contains one RBA, which usually is the location of the first free record or X'FF' record, currently in the Broadcast Dataset. The Free Search Record is for efficiency, to make it easier to find the next free (X'FF') record in the Broadcast Dataset, if it is needed for the writing of a new User Message or for the creating of a new Userid Directory Record. The X'FF' record is updated whenever messages are sent to, or deleted from, the Broadcast Dataset. So for now, we have shown you how the Broadcast Dataset record types work. Next month, we'll (hopefully) show you some tools, to make your life easier, in administering the Broadcast Dataset yourself. I wish all of you the best of everything, and I hope to see you here again, next month. * * * * * * * * * * * * * * * * * * * * * * * Figure 1. Types of Broadcast Dataset Records, as defined by their key. Key Value Type of Record Defined Macro --- ----- ---- -- ------ ------- ----- X'04' Broadcast Header Record IKJZT301 X'00' Global Notify Directory Record IKJZT302 X'02' Global Notice Record IKJZT303 X'05' Free Search Record IKJZT306 X'01' Userid Record IKJZT304 X'03' User Message Record (occupied) IKJZT305 X'FF' Free Message Record No Macro The X'FF' record has to have its relative position (on the track), in other words, the "R" of its CCHHR or TTR, as its first data byte, otherwise the Broadcast Dataset is considered "corrupted" by the system, and it will not function. This is why IBM says that you can't copy a Broadcast Dataset from one device type to another. The X'FF' records will come out on the wrong places in the track, if you do a dataset copy of the Broadcast Dataset using IBM tools.