Saturday, November 7, 2009

Tape Backup














Tape Backup


Installing and testing a tape backup system is one of those tasks that is either a breeze or a nightmare. If you don't run into any surprises, the process will take a few stress-free hours—not including, of course, the time spent carefully planning the system before even ordering the hardware. Installations don't always go smoothly, however. At the first device unavailable message, you might as well call home to say you'll be working late.


At first glance, you wouldn't expect a tape drive installation to be any more fraught with pitfalls than installation of a hard drive. However, because the tape drive is often added to a fully configured system—usually as something of an afterthought—you're more likely to bring any hidden problems to the forefront. Also, given the different nature of tape drives and the fact that you're more likely to disconnect and reconnect them, the devices can strain a SCSI chain that's already marginal.


In this tutorial, we'll look at some of the dangers lurking in the back of the SCSI bus (or channel), and in the process, get an overview of SCSI fundamentals.




The Scuzzy Spec


The Small Computer Systems Interface (SCSI, pronounced SKUH-zee) specification started as an attempt to provide a device-independent way to connect multiple devices to a computer, without requiring a separate device driver customized for each type of hard disk or tape device. While the goal of eliminating separate drivers remains elusive, SCSI does promote the use of much more intelligent devices that handle many of the details of data writing and reading and defect management. Thus, the software on the computer doesn't have to include separate logic to handle each different type of drive.


A SCSI bus can address up to eight devices, each of which can be classified as initiator (a device giving commands to other devices) or target (a device carrying out those commands). Most often, the host adapter will take the role of initiator and the attached drives will be the targets. But, some SCSI devices can alternate between being initiators and targets.


Total SCSI cable length should be less than 6 meters, or about 19.7 feet. When measuring cable length, include cables inside the computer and within external devices, such as autoloaders. Cables with different impedance values should not be used in the same chain or the signal may tend to be reflected at the junction. You'll save yourself trouble by using high-quality cables and keeping the total length of the SCSI chain as short as possible—much shorter than the 6 meters specified in the standard.






Terminators


Each end of the SCSI chain should be terminated. Terminating resistors keep the signal from reflecting back into the cable. Some of the hardest-to-find problems spring from improper termination; having too many, too few, or incorrect placement of terminators can cause unreliable operation. Also, bear in mind that improperly terminated SCSI chains may work fine for a time, but then fail when you add another device to the chain or use applications that stress the limits of the SCSI data transfer rate.


A SCSI bus with no termination isn't likely to work at all. A bus that's missing just one terminator will work in most cases, but it won't be as reliable with long cables or in an environment with a lot of electrical noise. The same holds true for a SCSI bus in which the terminators aren't at the very ends of the chain.


Remember that for proper termination, only the devices (drives or host adapter) at the ends of the daisy chain must have terminators installed. Note that many drives come with terminating resistor packs installed. If you use drives in external cabinets, make sure that the drives installed in those cabinets are properly configured. Usually, it's easiest to remove the termination from the drive itself and install a plug-type terminator on the external box.


If the host adapter controls one SCSI channel and both internal and external SCSI devices are installed, the devices at each end of the chain need to be terminated and the host adapter itself should not be terminated. Some SCSI host adapters simplify configuration by including separate internal and external SCSI channels. With these cards, the adapter and the last drive in each chain should be terminated.


The original SCSI specification called for passive terminators—a pair of resistors for each signal line on the SCSI bus. With its faster data transfer rates and tighter timings, the SCSI-2 specification introduced an alternate, more reliable form of termination called active termination. Incorporating one or more voltage regulators, active terminators provide much more consistent termination and are less susceptible to noise. Active terminators will work with SCSI or SCSI-2 channels. So, if you are experiencing hard-to-trace problems with SCSI devices, you may want to try replacing your passive terminators with active ones.


Improper termination isn't always the culprit when SCSI channels exhibit intermittent problems. The power supplies of some external SCSI cabinets can occasionally malfunction, causing unreliable operation of the drive and mimicking termination or SCSI ID problems with the SCSI channel. Other problems can arise from incorrect settings on the drives themselves.


Sometimes, adding a tape drive to a SCSI bus can suddenly cause the entire chain to operate more slowly. If you have a tape unit, CD-ROM, or other device attached to the SCSI bus, you should enable the disconnect feature on those devices. This allows the host-based adapter (HBA) to issue a command or series of commands to that device and then disconnect and return to servicing disk requests. If the disconnect feature is not enabled, the SCSI bus must wait for the device to return with a completion code, which may make the bus unable to fulfill other requests to talk to the drive.






SCSI IDS


Up to eight devices, including the host adapter, can attach to one SCSI channel. The SCSI ID must be different for each device on the same channel. The controller itself usually has ID 7. A bootable hard drive is usually set to ID 0. Other devices on the chain should have IDs that correspond to their priority; 0 has the lowest priority, and 7 has the highest.


This makes intuitive sense in the case of the controller, because it would obviously need the highest priority. However, with bootable hard drives, device priority may be confusing. The BIOS on many controllers will only make a drive with SCSI ID 0 bootable; this seems problematic because the device needing the highest priority is assigned the lowest. But, it turns out that SCSI priority isn't very important in normal operation. Most devices cooperate to keep the bus as free as possible, so arbitration priority is needed only as a last resort during device contention. In addition, arbitration is needed only at the beginning of a transaction between two devices, usually the host adapter and another SCSI device. While the two devices communicate, no other devices can access the SCSI bus.


SCSI ID is very important, even if arbitration priority isn't always a serious issue. Remember that each device, even internal drives, must have a unique ID. The ID also serves as the device address, a three-bit sequence that's included with each command issued to a device. Duplicate device IDs are a very common source of errors, and the problems they cause can be intermittent and hard to track down. This is especially true if you install drive mechanisms into do-it-yourself external SCSI cabinets and have incomplete information about the drive-select jumpers.


Installing a SCSI host adapter with multiple channels may ease the process of selecting unique IDs. Some SCSI cards use different channels, each supporting up to seven devices, for the internal and external connectors. Thus, you wouldn't need to worry about the IDs of internal devices when you install external SCSI devices. Separate channels can also help you segregate fast hard drives from slower devices, such as CD-ROMs and tape drives.


It's a good idea to keep tape drives on a different SCSI channel than your hard drives. This keeps fast hard drives from becoming burdened by slower devices. It's also a much safer configuration for emergency surgery on a tape drive. Although disconnecting a tape drive from the SCSI chain with the server power on is never recommended, in an emergency, you may have to. Having the tape drive segregated from the hard drives will at least ensure that you don't bring the whole file system down when you replace a jammed tape drive. Better yet, get a server that actually supports hot-swapping of SCSI devices.






Last Words


Some 8mm tape drives default to asynchronous transfer mode, while many host adapters default to synchronous transfer mode. If you power down the tape drive while the server is still running and then power it back on, the device will attempt to use its default asynchronous mode without renegotiating the transfer mode with the host controller. The next tape operation is then likely to lock up the workstation or server.


If there's no bootable hard disk on the SCSI bus, disable the SCSI adapter's BIOS and let the software driver control the SCSI devices.


Make sure that you are loading the latest version of the drivers for your host adapter. Tape backup programs will generally require ASPI (Advanced SCSI Programming Interface) drivers. The interface consists of two parts: a low-level, hardware-specific ASPI Manager that accepts ASPI commands and translates them into commands the adapter hardware understands; and an adapter-independent ASPI module. Although the ASPI module is adapter independent, it is generally customized to support a particular type of SCSI device, such as tape drives, CD-ROMs, or hard drives.






Feeling Kind Of SCSI: SCSI's New Generation


In the face of increasing speeds offered by hard drives, the SCSI specification has been updated. The SCSI-2 specification included methods for faster and wider data transfer and for more robust termination. The SCSI-3 specification, which is currently being developed, is intended to solidify some of the improvements needed to handle even faster data transfer, such as support for fiber optic interfaces. It will also add support for other types of peripherals.


Here are some of the SCSI-related terms you're likely to hear:



Differential SCSI vs. single-ended SCSI. These terms were defined by the original SCSI specification to support different types of SCSI interface cables. The most commonly encountered type is single-ended SCSI, which has one wire for each signal to be transmitted. Differential SCSI, in contrast, uses a pair of wires for each signal, providing greater immunity to electrical noise and supporting greater cable lengths.


A single SCSI bus supports either single-ended or differential devices; the host determines which type. You can't combine both types on the same chain. Most generic SCSI drives are single-ended SCSI devices.



Synchronous vs. asynchronous transfer. Defined in the original SCSI specification, synchronous transfers allow data rates of up to 5MBps on SCSI devices by allowing devices to transmit without waiting for acknowledgment from the other device—the acknowledgments should eventually catch up, but the transmitting device doesn't have to wait for each one. SCSI-2 expanded this concept to support rates of up to 10MBps. This 10MBps rate is generally called Fast SCSI.



Fast SCSI. By reducing some of the timing margins in the SCSI specification, SCSI-2 devices can transfer data faster than SCSI devices— 3MBps for asynchronous SCSI-2 transfers vs. 1.5MBps for SCSI, and up to 10MBps for SCSI-2 synchronous transfers. Fast SCSI generally refers to SCSI-2 devices capable of performing synchronous transfers faster than 5MBps.



Wide SCSI. The original SCSI specification called for a single cable serving as the backbone of the SCSI bus. This cable supported a data width of eight bits, or one byte. SCSI-2 also allows for transfers using wider data paths of 16 bits or 32 bits. However, this wider path entails the use of an additional 68-pin cable called the B-Cable. Not surprisingly, the original SCSI cable is called the A-Cable. Because wide transfers are automatically negotiated between devices, you can mix devices using different data widths on the same SCSI bus.


Because the B-Cable carries only data signals, Wide SCSI devices conforming to the SCSI-2 standard still use only eight bits for command, status, message, and arbitration lines. SCSI-3 will add a specification for a new type of cable, the P-Cable, that supports 16-bit arbitration, as well as 16-bit data transfers.




This tutorial, number 84, by Dave Fogle, was originally published in the August 1995 issue of LAN Magazine/Network Magazine.


















Configuration











Configuration


With any SAN, consideration for the balance between performance and capacity always must be paramount. If too much emphasis is placed on capacity, performance will surely suffer, so heed the word of your storage vendor about storage layout. In this chapter, we focus only on how to increase storage with a simple storage layout, and not on performance.


We use the following two servers to illustrate our concepts.


The particulars on Machine 1 are as follows:


[root@cyclops root]# uname -a
Linux cyclops 2.4.9-e.10custom-gt #4 SMP Mon Nov 1 14:17:36 EST 2004 \
i686 unknown
[root@cyclops root]# cat /etc/redhat-release
Red Hat Linux Advanced Server release 2.1AS (Pensacola)


Machine 2 looks like this:


atlorca4:~ # uname -a
Linux atlorca4 2.6.5-7.97-default #1 SMP Fri Jul 2 14:21:59 UTC 2004 \
ia64 ia64 ia64 GNU/Linux
atlorca4:~ # cat /etc/SuSE-release
SUSE LINUX Enterprise Server 9 (ia64)
VERSION = 9


The following representations outline the two servers within the SAN.


First, Machine 1 (Cyclops):


(Cyclops) Has two Emulex LP8000 HBAs
|-LP8000-|-WWN 10000000c9241327 ----> FCID 0x7b0f00 on Brocade 28000


Storage location for Brocade 28000 Domain 0x7b


Brocade 28000 Domain 0x7b port 0 -->--ISL --> Domain 0x78 Brocade 2800 \
Port 1
Domain 0x78 Brocade 2800 port 5 connects to >--- Storage array

|-LP8000-|-WWN 10000000c9286bda --> FCID 0x7f0d00 on Brocade 28000


Storage location for Brocade 28000 Domain 0x7f


Two ISL hopes:


Brocade 28000 Domain 0x7f port 0 -->--ISL --> Domain 0x7b Brocade 28000 \
port 1, then port 0 -->--ISL --> Domain 0x78 Brocade 2800 Port 1


Domain 0x78 Brocade 2800 port 5 connects to >--- Storage array


This design is nothing more than an example of fault-tolerant Host Bus Adapter (HBA). If we lose the storage port, our host loses access to the storage.


Then we have Machine 2 (atlorca4):


|-LP9802-|-WWN 10000000c93d3fc5 --> FCID 0x652d13 on Mcdata 6064 director \
port 41 (2d hex = 45 dec subtract 4 = 41)


Note



This calculation works on any McDATA switch, calculating the port number from the FCID area field. Many tricks exist for different switches, but they are beyond the scope of this chapter.




As you can see in the previous example, the storage array plugs into port 41 on FCID 0x652b13 of McDATA 6064, yielding 100% locality for this host.












5.7 Document-View



[ Team LiB ]










5.7 Document-View


The Document-View pattern is also known as the Document-View architecture. In this section we'll discuss a refined version of the Document-View pattern that allows for an event notification mechanism. This refined version is sometimes called the Observable-Observer pattern, or the Publisher-Subscriber pattern.


The problem arises when you have a number of different representations of the same data. How do we keep the representations in synch with each other?


The solution, as shown in Figure 5.9, is to have one Document
(or Publisher
) class that holds the core data, and to have a range of View
(or Subscriber
) classes that display the data. To smooth out our exposition, we'll write 'document' or 'view' to mean, respectively, a Document
object or a View
object.



Figure 5.9. The Document-View pattern





The document needs to be able to add and remove views from its active list. And it needs to have a UpdateAllViews
method that tells all of the views that some of the data may have changed.


A view needs to have a getDoc()
method that returns a pointer to the owner document. When the document calls UpdateAllViews, each view executes an OnUpdate
method which checks the data in the document and updates the state of the view accordingly.


Another aspect of the Document-View architecture is that the view not only needs to be able to access the data in the document, it should also be able to mutate the data in the document. Part of the implementation of the document mutators must be that when document data is changed, the document calls UpdateAllViews
so that all of the active views will show the new data. This acts as a roundabout way for the views to communicate with each other. We can represent this by a UML sequence diagram as shown in Figure 5.10.



Figure 5.10. Sequence diagram of a view editing a document





As this is our first sequence diagram, we need to mention that UML sequence diagrams are used to show how the objects in a program interact over time. The diagram is set up as a series of columns, with one column for each object. Each column has a vertical lifeline showing the lifetime of the object. Arrows are drawn from lifeline to lifeline to symbolize the passing of messages via method calls. We normally label a message with the name of a method being called, and this method is expected to be a member method of the class column that the message points to. Use a dotted arrow line when the caller object is not shown. A call that an object makes to itself is drawn as an arrow that starts and ends on the object's own lifeline. The labels at the heads of the columns can either be class names or, if you want to distinguish among multiple instances of a class, you can use object names which are written in the format Class:Object1.


In this diagram, we see how the View1 object can edit the Doc data and mutate it. The document mutator uses an UpdateAllViews
call to 'publish' the changed data out to both View1 and View2. Presumably there has been a call to Document::updateAllViews before the start of this sequence diagram, so that View1 is in fact looking at a current view of the Doc before beginning to edit it.



Documents and views in Windows programs


Most Windows programs use variations of the Document-View pattern to simultaneously show multiple views of multiple documents. Putting this a bit differently, the Document-View architecture allows you to have different views of the same set of data, and it also allows you to display different views of different sets of data.


In a Windows Document-View architecture program you can get new views in two ways. (a) You can use a command with a name like File | New or File | Open to open an additional document, or (b) you can use a command with a name like Window | New to open an additional view of the currently active document. In case (a) what you have is a completely new set of data inside the new window, while in case (b) you get a different view of the data of one of the windows you already had open (the window which currently had the focus, i.e. the window that had the highlighted caption bar).


Each onscreen window view shows the data in an associated document. It is possible to have several view windows showing the same document, but it is not possible to have one view window showing more than one document.


One can imagine, say, a financial analysis program in which you might want to view the same numerical data both as a table and as a bar graph at the same time. These would be two different views of the same document, with the document being the set of numerical data. Or consider a computer game in which you want to show both a 3D rendered view of what virtual player sees, and a 2D overview map of the landscape. Here again, we'd have two views of the same document, where the document might have information like the game level, the positions of the players in the landscape, and the players' scores and strengths. In a word-processing program, the document is the text you're working on. If you use a splitter window, then the two subwindows represent two different views of the same document. In a paint or photo-retouching program, the document is the image you're working on, and you have a variety of possible views showing, for instance, different zoom levels, different layers of the image, and so on.


Having the different views show the same data is not something that you get for free. You have to write code to make it happen. It used to be fairly hard to write a Document-View architecture program, but now, thanks to MFC and the 'AppWizard' (the Visual Studio tool for creating projects), it's pretty easy. When you use the AppWizard to generate some starting code for a new project, its default choice is to use the Document-View architecture. The default program architecture chosen by the AppWizard is called MDI. This uses the Document-View architecture.


In Windows, Document-View architecture programs used to keep all of their views of all their documents inside a single-frame window. But now it's becoming the fashion to have a different frame window for each document. In the versions of Word starting with Word 2000, for instance, you'll find that the program pops up completely different frame windows when you open different documents. Some programs, such as Macromedia Dreamweaver, even pop up separate frame windows for each view, visually shattering the program into something like a sea of dialog boxes. But under the hood and on their menus, these are still Document-View architecture programs in which one executable manages a set of documents, each with its own set of views.



The app, the doc, and the view in MFC


Table 5.1 summarizes how MFC sets up the Document-View architecture for the Pop Framework.


As we discuss below, not all of your application's data is supposed to go into the CDocument. A flag saying whether or not you want to mute the speaker might go into your CWinApp. And a flag saying whether you want to show you graphical objects as solids or as wire-frames might go into your CView. It's only the data that relates to the description of what you're looking at that goes into the CDocument.































Table 5.1. The application, the document, and the view in MFC.

Colloquial name



Pop class



Inherits from



Code is in



Application



CPopApp



CWinApp



Pop.*



Document



CPopDoc



CDocument



PopDoc.*



View



CPopView



CView



PopView.*





This raises the point that you may want to be able to refer to one of the classes from inside one of the others. Suppose, for instance, that one of our CPopView
methods wants to look at a _soundflag that lives inside CPopApp. And surely, our CPopView
is going to need to find the data that's in the CPopDoc. If we're writing code inside a CPopApp, CPopDoc, or CPopView
method, is there a way to talk about the other classes?


It turns out that in terms of navigating among the app, the docs, and the views there are four tasks that we normally care about.



  • First, we need (but not very often) a way for any doc or view to get a pointer to the app that owns them.


  • Second, we need a way for any view to get a pointer to its 'owner' doc.


  • Third, we need a way for a doc to tell all of its views to update themselves, and we prefer to do this without having to individually list the views.


  • Fourth, we need a way for a document to know which of its views, if any, is the active focus window of the user interface.



The first task is done by the global method ::AfxGetApp(), as in:



CPopApp* papp = (CPopApp*)(::AfxGetApp());//cast CWinApp*

The second task is accomplished by the CView::GetDocument()
method, as in:



CPopDoc* pdoc = GetDocument();

As it happens, you don't need the cast on GetDocument
; because GetDocument
is redefined for each child of CView
to include the cast. (To make this clear, you can look at the definition of CPopView::GetDocument()
in popview.h.)


The third task is accomplished by the CDocument::UpdateAllViews
method, which cascades a call to CView::OnUpdate
down to each of the doc's views.


The full prototype of this third method is void UpdateAllViews( CView* pSender,
LPARAM lHint = 0, CObject* pHint = NULL ). The first argument isn't used very often. The second argument is used for a document to signal to its views if it is in some different-looking state, for instance if a game is over, the doc might put a number into lHint to tell the views to change color. The third argument is a catch-all where a doc can put pretty much anything it likes to pass to its views. That is, a doc can wrap some information up inside a class object and then pass the view a pointer to the class with the information.


As we mention in Chapter 23: Programming Windows with MFC in Part II, there actually is a way to individually step through a doc's views, but this is a technique that you should use only rarely. Using UpdateAllViews
is a higher-level and cleaner way for your doc to pass information to its views.


The fourth task can be accomplished by a special CPopDoc::getActiveView()
method that we wrote for our CPopDoc
class; see the Levels of Windows section in Chapter 23 for details.



Documents and views in the Pop Framework


Using the Document-View architecture forces a programmer to think about where to declare his or her variables. In this subsection we talk about this issue in the Pop Framework.


Your program is normally going to have a number of variables that describe the data being displayed by the program as well as the current state of the program. These are the kinds of variables that you might once have made into global variables or into static variables living inside your main
function. In MFC programming you will usually put these variables either into your CDocument
class or into your CView
class � well, actually they go into your app's specific children of these classes (which are called CPopDoc
and CPopView
in our example program). Once in a while you might store a particular variable in the CWinApp
class or in your CMainFrame
class instead; an example of this kind of variable might be a global switch that specifies whether or not to pause your program when another program is in the foreground. But the overwhelming majority of your variables will live in your CDocument
and your CView. But in which one?


The CDocument
variables tend to be either the kinds of file variables that you might want to save, or the kinds of temporary helper objects that you might want to share among several views. And variables whose values are specific to an individual view go into the CView.


Let's say more about the Document-View distinction in terms of a computer game program such as we'll be writing in this book. In a computer game you'll often have an array of 'critters' moving around on top of a bitmap background. Each of your critters will have a position, a velocity, a health-index, and so on. (Normally one of the critters will represent you, the player, and its actions will be controlled by your input rather than by the program code. But it's still just a critter.) As the user plays the game, he or she will see the critters moving inside a window. It may be that if the user wants the game to run faster, he or she will have the choice of showing the critters in simple outline instead of in colorful detail. The variable controlling this choice would probably be stored at view level rather than at document level. Another example of a situation where there might be a view-specific variable might be the user's 'point of view'. This would be a factor if the critters' world is larger than the window, and the user can scroll the view this way and that. Or perhaps the world has a lot of detail and the user can zoom in or out. Or perhaps the game is three-dimensional, and the user will have the option of changing the angle of view.


Two views of a Pop Dambuilder game document






In our computer games, we'd expect the critters and the background bitmap information to live in the CDocument. But, as mentioned, the switch that determines whether or not to show the critters in detail would live in the CView, as would the variable (perhaps a real-valued rectangle or a matrix) that specifies the user's point of view. If you were to 'save' your game, you'd normally only want to save the states of the critters, that is the document data. But it could happen that you might want to save some information about the view as well, e.g. the current location of the player's point of view.


It isn't always easy to decide whether to put a given variable into the document or into the view, but as we go along in our example programs the process should become a little clearer. Very often there is no one 'absolutely right' way to program something. (But there are plenty of things that are absolutely wrong!) For a beginning programmer, the number of choices is daunting, and it's easy to feel paralyzed with indecision. Well, the only real way to learn is by doing, so go ahead and program, but keep an open mind and be willing to go back and rewrite what you did before. Another way of putting this is that learning programming is a matter of first making every possible mistake, so the faster you make your mistakes the faster you're learning!


Here's how the CPopDoc
updates the game. First, the stepDoc
method calls _pgame->step, where the cGame *_pgame
reference member object holds the data of the game document. And second, the stepDoc
uses UpdateAllViews
to update the views to display the newly updated _pgame data.



void CPopDoc::stepDoc(Real dt)
{
CPopView *pview = getActiveView();
_pgame->step(dt, pview); /* Move the critters for timestep dt.
Maybe add or delete some critters. Critters might use the
pview to sniff out the pixel colors near their current image
locations (rarely used). */
cTimeHint timehint(dt); //Wrap dt up so we can pass it to the views.
UpdateAllViews(NULL, 0, &timehint); /* Redraw all the views and
possibly animate their viewpoints with the dt inside
timehint. */
}

As a sequence diagram, this looks like Figure 5.11. Since we only have one object of each class type in this picture, we just label the columns with the class names.



Figure 5.11. Sequence diagram of the CPopDocument::stepDoc cascade






Controlling multiple documents and views


How do you fit the Document-View pattern into your application if you want more than document? And how do you send messages to the various pieces of the program?


One solution is to have an App
class that holds an array of Document
objects, and to have App, Document, and View
inherit from a base class Target. This is the architecture used by the MFC framework when you go for a MDI.


Pop showing two game documents






The idea is to use an App
class in addition to a Document
and a View
class. In the MFC Application Framework, these classes are called CWinApp, CDocument, and CView.


What we have here is close to a pattern called 'model-view-controller.' In the model-view-controller pattern the 'model' plays the role of the Document, the 'view' is a View
in the same sense we've already talked about, and the 'controller' is an abstraction of the user interface controls. Stretching things a bit, you might think of the controller as being the App, so that Document-View-App becomes a close analog of model-view-controller.


This analogy is, however, imperfect, because in the specific example of MFC we actually process user commands with any of the three Document-View-App components, which in MFC are the CDocument
objects, the CView
objects, and a CWinApp
object. In an MFC program, all three of these classes can process messages and act like a 'controller'.


In any case, this is a good place to say a bit about how MFC processes user commands. In MFC there is a general base class called CCmdTarget. A CCmdTarget
object is characterized as being an object that you can send Windows messages to. Put differently, a CCmdTarget
is something that can process, say, menu item selection messages such as OnCommandGamePlaySounds. (As it so happens, in the Pop program this message was originally processed by the CPopDoc, and later we changed it so that the message is processed by the CPopApp.) Now we can send a message either to a document, to the application, or to a window, and Figure 5.12 expresses that notion. Just to make the diagram a little bigger, we've put in the three child classes CPopDoc, CPopApp, and CPopView
as well.



Figure 5.12. Inheritance diagram in a multiple document pattern





This diagram shows inheritance; now let's talk about composition and navigation. As we've already said, the CWinApp
class corresponds to the program as a whole, and the CDocument
class corresponds to the files that the program currently has open. Although a CWinApp
does not have a set of CDocument
objects as explicit members, we certainly think of it as associating with the CDocument
class. As for navigation, MFC happens to have a global ::AfxGetApp
method that returns the current CWinApp, so we can navigate from CDocument
to CWinApp. And, although it's not simple to describe, there is also an accessor-like process by which a CWinApp
can walk through a list of its CDocument
objects, so we can say that we can navigate from CWinApp
to CDocument. (If you're curious about the details of Windows programs, see Chapter 23: Programming Windows with MFC). So we draw a composition line in one direction with a navigation line coming back the other way. A CWinApp
can open as many views as we like (by using Window | New), but a CDocument
has only one associated CWinApp.
So we put a * by CDocument
at the end of the composition line. This is shown in Figure 5.13.



Figure 5.13. App and documents





This is entirely analogous to how a Document
relates to a View
(Figure 5.14).



Figure 5.14. Document and views





For the sake of completeness, let's draw one more UML diagram (Figure 5.15) showing some of the relationships among our Pop Framework MFC classes.



Figure 5.15. Class diagram of the Pop Framework MFC classes





You might say that this UML diagram is primarily about the Windows operating system, and the UML diagram of the Pop Framework classes in the last chapter was primarily about the Pop program. It make sense that CPopDoc
and CPopView
appear in both diagrams, because these classes are designed by MFC to contain, respectively, the application's data and the application's appearance. The CPopView, your app's onscreen image, is where it makes contact with the Windows operating system.






    [ Team LiB ]



    UML Class Diagrams











     < Day Day Up > 














    UML Class Diagrams



    The Unified Modeling Language (UML) [Fowl03] is widely used for analysis and design of software applications. An important type of UML diagram is the class diagram. A class diagram describes the types of objects in a system and the various types of static relationships that exist among them.











    Class A rectangular box denoting the name of the class and optionally its attributes and operations. Abstract classes' names are labeled in italics along with their corresponding abstract methods.











    Operation. Operation names are written in the class boxes. They denote the methods of classes. Abstract operations, that is, those that only provide the interface for polymorphism, are denoted by italics.











    Attributes. Attribute names are written in the class boxes. They denote the instance variables of a class.











    Association. A line that connects classes. Associations can be optional or multiple. A number at the end of an association denotes its cardinality. Association of classes is used to show any type of class relationship except aggregation, composition, or inheritance.











    Composition. A solid diamond shape at the termination of an association line denotes that the class at the other end of the association is part of the class and has the same lifetime.











    Dependency. A dependency indicates that a class uses the interface of another class for some purpose.











    Realization. A realization represents the relationship between a specification and its implementation.











    Inheritance. Inheritance is denoted by a triangle at the top of an association line. The apex of the triangle points to the superclass.
























     < Day Day Up > 



    CRITICAL SKILL 8.4 Store XML in Oracle XML DB


    Team Fly 


    Page 283




    3. When can the xmlattributes() function be called?



    4. What corresponding SQL clause must accompany an xmlagg() function?



    CRITICAL SKILL 8.4
    Store XML in Oracle XML DB



    Databases are relational and XML is hierarchical, so prior to the introduction of Oracle XML DB there had been no simple, elegant way to integrate the two. Traditionally, developers have had two choices: either use a parser to deconstruct the document data into relational data and store it as such in the database, or store the entire document as a text file, preserving its text-based structure. Oracle XML DB starts it all off by first solving the problem of representing an XML document in its native format—the XMLType.



    The Native XMLType



    The XMLType was created to be able to preserve the XML paradigm while getting the benefits of relational performance and scalability. It is a native server data type that allows the database to understand that a column or table contains XML—in the same way that the DATE data type allows the database to understand that a column contains a date. The twist is that the XMLType also provides methods that allow common operations such as schema validation and XSL transformations to be performed on XML content.



    The XMLType data type can be used just like any other data type, such as when creating a column in a relational table, when declaring PL/SQL variables, and when defining and calling PL/SQL procedures and functions. Since XMLType is an object type, it is also possible to create a table of XMLType. The following listing shows how to create a simple table with an XMLType column:




    SQL> create table purchase_order
    2 (
    3 po_no number(9),
    4 po_file xmltype
    5 )









    Progress Check Answers


    1. The hierarchical data structure is a data structure that has several levels arranged in a tree-like structure.


    2. xmlelement() is used to define all elements with the XML type. All XML types start with a root element.


    3. The xmlattributes() function can only be called within an xmlelement() function call. The xmlattributes() function builds attributes for an element.


    4. xmlagg() must be accompanied by a group by clause.




    Team Fly 

    9-Ball

    Chapter 18. 9-Ball




    Nine-ball is just one of the many types of pool games but is probably the most popular among professional pool players. Most nonprofessionals, at least in the United States, tend to be more familiar with 8-ball. I programmed 9-ball instead of 8-ball because 9-ball only uses 10 balls, as opposed to the 16 used in 8-ball. Through my tests I determined that having 16 balls is much too CPU intensive in Flash. You may remember that in Chapter 2, "The Plan: From Idea to Design," we listed this very problem as a possible programming deterrent; having too many balls on the table could cause a problem that we would have needed to work around. The workaround, in that case, was changing the game.


    This game requires more knowledge than just about any other game in this book: knowledge of physics, collision detection, collision reactions, and multiplayer systems. If you have trouble understanding the ActionScript used in this game, I recommend that you review the prerequisite chapters.





    7.2 The Rayleigh Model




    I l@ve RuBoard










    7.2 The Rayleigh Model


    The Rayleigh model is a member of the family of the Weibull distribution. The Weibull distribution has been used for decades in various fields of engineering for reliability analysis, ranging from the fatigue life of deep-groove ball bearings to electron tube failures and the overflow incidence of rivers. It is one of the three known extreme-value distributions (Tobias, 1986). One of its marked characteristics is that the tail of its probability density function approaches zero asymptotically, but never reaches it. Its cumulative distribution function (CDF) and probability density function (PDF) are:








    where m is the shape parameter, c is the scale parameter, and t is time. When applied to software, the PDF often means the defect density (rate) over time or the defect arrival pattern and the CDF means the cumulative defect arrival pattern.


    Figure 7.1 shows several Weibull probability density curves with varying values for the shape parameter m. For reliability applications in an engineering field, the choice of a specific model is not arbitrary. The underlying assumptions must be considered and the model must be supported by empirical data. Of the Weibull family, the two models that have been applied in software reliability are the models with the shape parameter value m = 2 and m = 1.



    Figure 7.1. Weibull Probability Density





    The Rayleigh model is a special case of the Weibull distribution when m = 2. Its CDF and PDF are:








    The Rayleigh PDF first increases to a peak and then decreases at a decelerating rate. The c parameter is a function of tm, the time at which the curve reaches its peak. By taking the derivative of f(t) with respect to t, setting it to zero and solving the equation, tm can be obtained.








    After tm is estimated, the shape of the entire curve can be determined. The area below the curve up to tm is 39.35% of the total area.


    The preceding formulas represent a standard distribution; specifically the total area under the PDF curve is 1. In actual applications, a constant K is multiplied to the formulas (K is the total number of defects or the total cumulative defect rate). If we also substitute








    in the formulas, we get the following. To specify a model from a set of data points, K and tm are the parameters that need to be estimated.














    It has been empirically well established that software projects follow a lifecycle pattern described by the Rayleigh density curve (Norden, 1963; Putnam, 1978). Early applications of the model in software were mainly for staffing estimation over time for the life cycle of software projects. More recent work demonstrated that the defect removal pattern of software projects also follows the Rayleigh pattern.


    In 1982 Trachtenberg (1982) examined the month-by-month error histories of software projects and found that the composite error pattern of those projects resembled a Rayleigh-like curve. In 1984 Gaffney of the IBM Federal Systems Division reported the development of a model based on defect counts at six phases of the development process commonly used in IBM: high-level design inspections, low-level design inspections, code inspections, unit test, integration test, and system test. Gaffney observed that the defect pattern of his data by the six-phase development process followed a Rayleigh curve. Following the system test phase is the phase of field use (customer use). The number of latent defects in the field is the target for estimation.


    By developing a Rayleigh model to fit his data, Gaffney was able to project the expected latent defects in the field. Putnam's work includes the application of the Rayleigh model in estimating the number of software defects, in addition to his well-known work on software size and resource estimation (Putnam and Myers, 1992). By validating the model with systems for which defect data are available (including the space shuttle development and radar development projects), Putnam and Myers (1992) found that the total actual defects were within 5% to 10% of the defects predicted from the model. Data fits of a few other systems, for which the validity of the data is doubtful, however, were not so good. As in Trachtenberg's study, the time unit for the Rayleigh model in Putnam and Myers's application is expressed in terms of months from the project start.


    Figure 7.2 shows a Rayleigh curve that models the defect removal pattern of an IBM AS/400 product in relation to a six-step development process, which is very similar to that used by Gaffney. Given the defect removal pattern up through system test (ST), the purpose is to estimate the defect rate when the product is shipped: the post general-availability phase (GA) in the figure. In this example the X-axis is the development phase, which can be regarded as one form of logical equivalent of time. The phases other than ST and GA in the figure are: high-level design review (I0), low-level design review (I1), code inspection (I2), unit test (UT), and component test (CT).



    Figure 7.2. Rayleigh Model










      I l@ve RuBoard