Using the Application Program Interface


Chapter 3. Using the Application Program Interface

The API package that you receive includes a sample application. This chapter uses examples that are taken from that sample application to demonstrate how to use the API. You should be familiar with this chapter before you design or write an application that uses the API.

Note:The examples in this chapter are program fragments that demonstrate how you use the API functions in context. Many of the examples in this chapter are taken from the UNIX sample application. The program fragments on other platforms might look somewhat different; some of these examples are shown.

Determining Size Limits

Certain data structures or fields in the API have size limits. These structures are often names or other text fields that cannot exceed a predetermined length. Examples of fields with such limits include:

These limits are defined as constants within the header file, dsmapitd.h. Any storage allocation should be based on these constants rather than numbers you enter. Refer to Appendix A, API Type Definitions Source File for further information and a list of the current constants.


Maintaining Version Control in the API

All APIs have some form of version control, and Tivoli Storage Manager is no exception. The API version that you use in your application must be compatible with the version of the API library that is installed on the end user workstation.

The dsmQueryApiVersionEx should be the first API call that you enter when you use the API. This call:

The API is designed to be upwardly compatible. Applications written to older versions or releases of the API library will operate correctly if the end user is running a newer version. An exception to this is an OS/2 application that is compiled with the Version 2 DLL. This will not run with the adsmv3.dll because of memory model incompatibility. See "Summary of Code Changes" for differences between levels.

Determining the release of the API library is very important because some releases might have different memory requirements and data structure definitions. Downward compatibility is unlikely. See Table 9 for information about your platform.

Table 9. Platform Information

Platform Description
Intel The dsmtca is not used. The message files must be at the same level as the library (DLL).
UNIX The API library, the Trusted Communication Agent module (dsmtca), and the message files must be at the same level.

The dsmQueryApiVersionEx call returns the version of the API library that is installed on the end user workstation. You can then compare the returned value with the version of the API that the application client is using.

The API version number of the application client is entered in the compiled object code as a set of four constants defined in dsmapitd.h:

   DSM_API_VERSION
   DSM_API_RELEASE
   DSM_API_LEVEL
   DSM_API_SUB_LEVEL

See Appendix A, API Type Definitions Source File.

The API version of the application client should be less than, or equal to, the API library that is installed on the user's system. Be careful about any other condition. You can enter the dsmQueryApiVersionEx call at any time, whether the API session has been started or not.

Data structures that the API uses also have version control information in them. Those structures that can grow in size have version information as the first field within the structure. This permits the API to verify the version of the structure that is used.

Figure 1 demonstrates the type definition of the structure, dsmApiVersionEx from the header file, dsmapitd.h. The example then defines a global variable that is named apiLibVer. It also demonstrates how you can use it in a call to dsmQueryApiVersionEx to return the version of the end user's API library. Finally, the returned value is compared to the API version number of the application client.

Figure 1. An Example of Obtaining the Version Level of the API

typedef struct
{
        dsUint16_t stVersion;     /* Structure version                */
        dsUint16_t version;       /* API version                      */
        dsUint16_t release;       /* API release                      */
        dsUint16_t level;         /* API level                        */
        dsUint16_t subLevel;      /* API sub level                    */
} dsmApiVersionEx;
 
dsmApiVersionEx apiLibVer; 
 
memset(&apiLibVer,0x00,sizeof(dsmApiVersionEx));
dsmQueryApiVersionEx(&apiLibVer);
 
/* check for compatibility problems */
dsInt16_t appVersion= 0, libVersion = 0; 
 
  appVersion = (DSM_API_VERSION * 1000) + (DSM_API_RELEASE * 100) +
               (DSM_API_LEVEL * 10) + (DSM_API_SUBLEVEL)   
  libVersion = (apiLibVer.version * 1000) + (apiLibVer.release * 100) +
                  (apiLibVer.level * 10) + (apiLibVer.subLevel);
 
 
   if (libVersion < appVersion)
   {
      printf("\n***********************************************************\n");
      printf("The TSM API library is lower than the application version\n");
      printf("Install the current library version.\n");
      printf("*************************************************************\n");
      return 0;
   }
 
 
printf("* API Library Version = %d.%d.%d.%d  *\n",
     apiLibVer.version,
     apiLibVer.release,
     apiLibVer.level,
     apiLibVer.subLevel);

Using Multi-Threading

Note:When you run applications that assume a multi-threaded API, use the dsmQueryAPIVersionEx call. This verifies that the level of the API is 3.1.6 or a higher level.

The multi-threaded API permits applications to create multiple sessions with the TSM server within the same process. The API can be entered again. Any calls can run in parallel from within different threads. To run the API in multi-threaded mode, set the mtflag value to DSM_MULTITHREAD on the dsmSetUp call. The dsmSetUp call must be the first call after the dsmQueryAPIVersionEx call. This call must return before any thread calls the dsmInitEx call. When all threads complete processing, enter a call to dsmCleanUp. The primary process should not end before all the threads complete processing. See callmt1.c in the sample.

Note:The default for the API is single-thread mode. If an application does not call dsmSetUp with the mtflag value set to DSM_MULTITHREAD, the API permits only one session for each process.

You cannot use the Trusted Communication Agent in multi-thread mode. If you want to use passwordaccess generate, you must be a TSM-Authorized user.

Once dsmSetUp successfully completes, the application can begin multiple threads and enter multiple dsmInitEx calls. Each dsmInitEx call returns a handle for that session. Any subsequent calls on that thread for that session must use that handle value. Certain values are process-wide, environmental variables (values that are set on dsmSetUp). Each dsmInitEx call will parse options again. Each thread can run with different options by specifying an overwrite file or an options string on the dsmInitEx call. This enables different threads to go to different servers, or use different node names.

Note:On Netware, we recommend setting the thread stack to 32K or greater. The dynamic reallocation of thread stack is not reliable. The Netware server stops a program because of errors.

Using Signals

It is the responsibility of the application to handle signals from the user or the operating system. If the user enters a ctrl-c, the application should catch the signal and send dsmTerminate calls for each of the active threads. Then, call dsmCleanUp to exit. Failure to do this might result in unexpected results on the server if sessions are not closed properly.

Note:We recommend that the application install signal handlers such as, SIGPIPE and SIGUSR1, for signals that cause the application to end. The application then receives the return code from the API.

You can use the the child process, Trusted Communication Agent (TCA) if passwordaccess is set to generate. When the TCA is used, TSM uses the SIGCLD signal. If you want your application to use the SIGCLD signal, be aware of potential interference from the TSM program and how it uses SIGCLD. See "Session Security" for more information about using the TCA.


Starting or Ending a Session

The TSM program is a session-based program, and all activities must be performed within a TSM session. To start a session, the application starts the dsmInitEx call. This call must be performed before any other API call other than dsmQueryApiVersionEx, dsmQueryCliOptions, or dsmSetUp.

The dsmQueryCliOptions function can only be called before the dsmInitEx call. It returns the values of important options, such as option files, compression settings, and communication parameters. The dsmInitEx call sets up a session with the server as indicated in the parameters that are passed in the call or defined in the options files.

The client node name, the owner name, and the password parameters are passed to the dsmInitEx call. The owner name is case-sensitive, but the node name and password are not. The application client nodes must be registered with the server before starting a session.

Each time an API application client starts a session with the server, the client application type is registered with the server. We recommend that the application type value contain an operating system abbreviation because this value is entered in the "platform" field on the server. The maximum string length is DSM_MAX_PLATFORM_LENGTH.

The dsmInitEx function call establishes the TSM session with the API configuration file and option list of the application client. The application client can use the API configuration file and option list to set a number of TSM options. These values override the values that are set in the user's configuration files at installation time. They can not change the options that the TSM administrator defines. If the application client does not have its own configuration file and option list, you can set both of these parameters to NULL. For more information about configuration files, see Understanding Configuration Files and Options Files.

The dsmInitEx function call establishes the TSM session, using additional parameters that permit extended verification.

The dsmQuerySessOptions call returns the same fields as the dsmQueryCliOptions call. It can be sent only within a session. The values reflect the client options that are valid during that session, from option files, and from any overrides from the dsmInitEx call.

Once a session starts, the application can send a call to dsmQuerySessInfo to determine the server parameters that are set for this session. Items such as the policy domain and transaction limits are returned to the application with this call.

End sessions with a dsmTerminate call. This closes any connection with the server and frees all resources that are associated with this session.

Session Security

Tivoli Storage Manager, a session-based system, has security components that permit applications to start sessions in a secure manner. These security measures prohibit unauthorized access to the server and help to insure system integrity.

Every session that is started with the server must complete a sign-on process. This sign-on process requires the use of a password. When the password is coupled with the node name of the client, it insures proper authorization when it connects to the server. The application client provides this password to the API to start the session.

Two methods of password processing are available: passwordaccess prompt, or passwordaccess =generate. If you use the passwordaccess prompt option, you must include the password value on each dsmInitEx call. Or, you can supply the node name and owner name on the dsmInitEx call.

Passwords have expiration times associated with them. If a dsmInitEx call fails with a password-expired return code (DSM_RC_REJECT_VERIFIER_EXPIRED), the application client must enter the dsmChangePW call. This will update the password before the session can be established successfully. The example in Figure 4 demonstrates the procedure to change a password by using dsmChangePW. The login owner must be root or TSM-Authorized to change the password.

The second method, passwordaccess generate, encrypts and stores the password value in a file. The node name and owner name cannot be supplied on the dsmInitEx call, and the system default values will be used. This protects the security of the password file. When the password expires, the generate parameter creates a new one and updates the password file automatically.

For UNIX: Only the root user or the TSM-Authorized user can change the password when using passwordaccess prompt. Only the root user or the TSM-Authorized user can start the password file when using passwordaccess= generate. You can use the Trusted Communication Agent (TCA) child process for password processing. The application should be aware of this because a child process and the SIGCLD signal are used. The TCA is not used in these situations:

The example in Figure 2 defines a number of global and local variables and then uses them in calls to dsmInitEx and dsmTerminate. The dsmInitEx call takes a pointer to dsmHandle for one of its parameters, while the dsmTerminate call takes the dsmHandle itself. The example in Figure 3 displays the details of rcApiOut. The function, rcApiOut, calls the API function dsmRCMsg, that translates a return code into a message. The rcApiOut call then prints the message for the user. A version of rcApiOut is included in the API sample application. The dsmApiVersion function is a type definition that is found in the header file, dsmapitd.h.

Figure 2. An Example of Starting and Ending A Session

dsmApiVersionEx * apiApplVer  ?right
char           *node;
char           *owner;
char           *pw;
char           *confFile = NULL;
char           *options = NULL;
dsInt16_t      rc = 0;
dsUint32_t     dsmHandle;
dsmInitExIn_t  initIn;
dsmInitExOut_t initOut;
char           *userName;
char           *userNamePswd;
 
memset(&initIn, 0x00, sizeof(dsmInitExIn_t));
memset(&initOut, 0x00, sizeof(dsmInitExOut_t));
memset(&apiApplVer,0x00,sizeof(dsmapiVersionEx));
 
apiApplVer.version = DSM_API_VERSION;  /* Set the applications compile */
apiApplVer.release = DSM_API_RELEASE;  /* time version.                */
apiApplVer.level   = DSM_API_LEVEL;
apiApplVer.subLevel= DSM_API_SUBLEVEL;
 
printf("Doing signon for node %s, owner %s, with password %s\n",
       node,owner,pw);
 
initIn.stVersion = dsmInitExInVersion;
initIn.dsmApiVersionP = &apiApplVer
initIn.clientNodeNameP = node;
initIn.clientOwnerNameP = owner ;
initIn.clientPasswordP = pw;
initIn.applicationTypeP = "Sample-API AIX";
initIn.configfile = confFile;
initIn.options = options;
initIn.userNameP = userName;   
initIn.userPasswordP = userNamePswd;
 
rc = dsmInitEx(&dsmHandle, &initIn, &initOut);
 
if (rc == DSM_RC_REJECT_VERIFIER_EXPIRED)
{
   printf("*** Password expired. Select Change Password.\n");
   return(rc);
}
else
if (rc)
{
   printf("*** Init failed: ");
   rcApiOut(dsmHandle, rc);   /* Call function to print error message */
   dsmTerminate(dsmHandle);       /* clean up memory blocks */
   return(rc);
}

Figure 3. Details of rcApiOut

void rcApiOut (dsUint32_t handle, dsInt16_t rc)
{
     char *msgBuf ;
 
     if ((msgBuf = (char *)malloc(DSM_MAX_RC_MSG_LENGTH+1)) == NULL)
     {
          printf("Abort:  Not enough memory.\n") ;
          exit(1) ;
      }
 
      dsmRCMsg(handle, rc, msgBuf);
      printf("%s\n",msgBuf);
      free(msgBuf) ;
      return;
}

Figure 4. An Example of Changing A Password

printf("Enter your current password:");
gets(current_pw);
printf("Enter your new password:");
gets(new_pw1);
printf("Enter your new password again:");
gets(new_pw2);
/* If new password entries don't match, try again or exit. */
/* If they do match, call dsmChangePW.                          */
 
rc = dsmChangePW(dsmHandle,current_pw,new_pw1);
if (rc)
{
   printf("*** Password change failed.  Rc = %i\n",rc);
}
else
{
   printf("*** Your new password has been accepted and updated.\n");
}
return 0;

Identifying the Object

The TSM server, an object storage server whose primary function is to efficiently store and retrieve named objects, has two main storage areas, database and data storage, to meet this requirement:

Each object that is stored on the server has a name associated with it. The client controls the following key components of that name:

When making decisions about naming objects for an application, you might need to use an external name for the full object names to the end user. Specifically, the end user might need to specify the object in an Include or Exclude statement when the application is run. The exact syntax of the object name in these statements is platform-dependent. On the OS/2 and Windows platforms, the drive letter associated with the file space rather than the filespace name itself is used in the Include or Exclude statement. On the Novell and AS/400 platforms, the first character of the low-level name must be a forward slash (/).

Filespace Name

The filespace name is one of the most important components. It can be the name of a file system or disk drive, or any other high-level qualifier that groups related data together. Tivoli Storage Manager uses the file space to identify the file system or disk drive on which the data is located. In this way, actions can be performed on all entities within a file space, such as querying all objects within a specified file space. Because the file space is such an important component of the TSM naming convention, TSM has special calls to register, update, query, and delete file spaces.

The server also has administrative commands to query the file spaces on any node in TSM storage, and delete them if necessary. All data stored by the application client must have a filespace name associated with it. Select the name carefully to group similar data together in the system.

To avoid possible interference, an application client should select different filespace names from those that a backup-archive client would use. The application client should publish its filespace names so that end users can identify the objects for Include and Exclude statements, if necessary.

Note:On Intel platforms, a drive letter is associated with a file space. When you register or update a file space, you must supply the drive letter. Because the Include-Exclude list refers to the drive letter, you must keep track of each letter and its associated file space. In the sample program dapismp, the drive letter is set to 'G' by default.

For more information, see the sample program installed on your system.

High-Level and Low-Level Names

Two other components of the object name are the high-level name qualifier and the low-level name qualifier. The high-level name qualifier is the directory path in which the object belongs, and the low-level name qualifier is the actual name of the object in that directory path. When the filespace name, high-level name, and low-level name are concatenated, they must form a syntactically correct name on the operating system on which the client runs. It is not necessary for the name to exist as an object on the system or resemble the actual data on the local file system. However, the name must meet the standard naming rules to be properly processed by the dsmBindMC calls. See "Understand Backup And Archive Objects" for naming considerations.

Object Type

The object type identifies the object as either a file or a directory. A file is an object that contains both attributes and binary data, and a directory is an object that contains only attributes.

Following are four examples of object names. The first example displays what the application client would code on a UNIX platform:

   /myfs/highlev/lowlev

The second example displays what the application client would code on a Windows or OS/2 platform:

   "myvol\\highlev\\lowlev"
Note:On Windows and OS/2, you must use a double backslash because a backslash is the escape character. The double backslashes are translated to single backslashes. Filespace names start with a slash on the UNIX platform, but do not start with a slash on the Windows platform.

The third example displays what the application client would code on a Novell NetWare platform:

   myvol:/highlev/lowlev

The fourth example displays what the application client would code on the AS/400 platform:

   myfs/highlev/lowlev

Accessing Objects

Each object has an owner name associated with it. The rules determining what objects are accessed depend on what owner name is used when a session is started. Use this session owner value to control access to the object.

The session owner is set during the call to dsmInitEx in the clientOwnerNameP parameter. If you start a session with dsmInitEx owner name of NULL and you use passwordaccess prompt, that session owner is handled with session (root or TSM-Authorized) authority. This is also true if you log in with a root ID or TSM-authorized ID and you use passwordaccess generate. This session can perform any action on any object that is owned by this node regardless of the actual owner of that object.

If a session is started with a specific owner name, the session can only perform actions on objects that have that object owner name associated with them. Backups or archives into the system all must have this owner name associated with them. Any queries performed return only the values that have this owner name associated with them. The object owner value is set during the dsmSendObj call in the Owner field of the ObjAttr structure. An owner name is case-sensitive. Table 10 summarizes the conditions under which a user has access to an object.


Table 10. Summary of User Access to Objects

Session Owner Object Owner User Access
NULL (Root, system owner) " " (Empty string) Yes
NULL Specific name Yes
Specific name " " (Empty string) No
Specific name Same name Yes
Specific name Different name No

Accessing Across Nodes and Across Owners

Three function calls, dsmSetAccess, dsmDeleteAccess, and dsmQueryAccess support cross-node, cross-owner access on the same platform. These functions, along with the -fromnode and -fromowner string options that are passed on dsmInitEx, permit a complete cross-node query, restore and retrieve process through the API. For example, User A on node A uses the dsmSetAccess function call to give access to its backups under the /db filespace to User B from Node B. The access rule is displayed as:

ID Type Node User Path
1 Backup Node B User B /db/*/*

When User B logs on at Node B, the option string to dsmInitEx is:

   -fromnode=nodeA -fromowner=userA

These options are set for this session. Any queries will access the filespaces, and files of Node A. Backups and archives are not permitted. Only query, restore, and retrieve processes are permitted from the filespaces for which User B has access. See the individual function calls and dsmInitEx for more information.

Note:On UNIX, you can specify -fromowner=root in the option string that is passed on the dsmInitEx function call. This permits non-root users access to files that the root owns if a set access was performed.

Managing File Spaces

Because the file space is so important to the operation of the system, a separate set of calls is used to register, update, and delete filespace identifiers. Before you can store any objects that are associated with a file space on the system, you must first register the file space with TSM. Use the dsmRegisterFS call to accomplish this task. See Identifying the Object for more information.

The filespace identifier is the top-level qualifier in a three-part name hierarchy. Grouping related data together within a file space makes management of that data much easier. For example, either the application client or the TSM server administrator can delete a file space and all the objects within that file space.

File spaces also permit the application client to provide information about the file space to the server that the TSM administrator can then query. This information is returned on the query in the qryRespFSData structure and includes:

Type Definition
fstype The filespace type. This field is a character string that the application client sets.
fsAttr[platform].fsInfo A client information field used for client-specific data.
capacity The total amount of space in the file space.
occupancy The amount of space currently occupied in the file space.
backStartDate The time stamp when the latest backup started (set by sending a dsmUpdateFS call).
backCompleteDate The time stamp when the latest backup completed (set by sending a dsmUpdateFS call).

Using capacity and occupancy depends on the application client. Some applications might not need information about the size of the file space, in which case these fields can default to zero. See Querying the TSM System for more information about querying file spaces.

After a file space is registered with the system, you can back up, or archive objects at any time. We recommend that you call dsmUpdateFS to update the occupancy and the capacity fields of the file space after a backup or archive operation. This ensures that the values for the occupancy and capacity of the file system are current. You can also update the fsinfo, backupstart, and backupcomplete fields.

If you want to monitor your last backup dates, enter a dsmUpdateFS call before starting your backup. Set the update action to DSM_FSUPD_BACKSTARTDATE. This will force the server to set the backStartDate field of the file space to the current time. After the backup is complete for that file space, enter a dsmUpdateFS call with the update action that is set to DSM_FSUPD_BACKCOMPLETEDATE. This will time stamp the end of the backup.

If a file space is no longer needed, you can delete it with the dsmDeleteFS command. On the UNIX platform, only the root user or TSM-Authorized user can delete file spaces.

The examples in Figure 5 demonstrate how to use the three filespace calls for UNIX. For an example of how to use the three filespace calls for Intel, see the sample program code installed on your system.

Figure 5. An Example of Working With File Spaces

/*  Register the file space if it has not already been done.  */
 
dsInt16        rc;
regFSData    fsData;
char         fsName[DSM_MAX_FSNAME_LENGTH];
char         smpAPI[] = "Sample-API";
 
strcpy(fsName,"/home/tallan/text");
memset(&fsData,0x00,sizeof(fsData));
fsData.stVersion = regFSDataVersion;
fsData.fsName = fsName;
fsData.fsType = smpAPI;
strcpy(fsData.fsAttr.unixFSAttr.fsInfo,"Sample API FS Info");
fsData.fsAttr.unixFSAttr.fsInfoLength =
       strlen(fsData.fsAttr.unixFSAttr.fsInfo) + 1;
fsData.occupancy.hi=0;
fsData.occupancy.lo=100;
fsData.capacity.hi=0;
fsData.capacity.lo=300;
 
rc = dsmRegisterFS(dsmHandle,fsData);
if (rc == DSM_RC_FS_ALREADY_REGED) rc = DSM_RC_OK;     /* already done */
if (rc)
{
   printf("Filespace registration failed: ");
   rcApiOut(dsmHandle, rc);
   free(bkup_buff);
   return (RC_SESSION_FAILED);
}
 
 
/* Update the file space. */
 
dsmFSUpd     updFilespace;         /* for update FS */
 
updFilespace.stVersion = dsmFSUpdVersion;
updFilespace.fsType = 0;             /* no change */
updFilespace.occupancy.hi = 0;
updFilespace.occupancy.lo = 50;
updFilespace.capacity.hi = 0;
updFilespace.capacity.lo = 200;
strcpy(updFilespace.fsAttr.unixFSAttr.fsInfo,
       "My update for filespace") ;
updFilespace.fsAttr.unixFSAttr.fsInfoLength =
       strlen(updFilespace.fsAttr.unixFSAttr.fsInfo);
 
updAction = DSM_FSUPD_FSINFO |
            DSM_FSUPD_OCCUPANCY |
            DSM_FSUPD_CAPACITY;
 
rc = dsmUpdateFS(handle,fsName,&updFilespace,updAction);
printf("dsmUpdateFS rc=%d\n", rc);
 
 
/*  Delete the file space.  */
 
printf("\nDeleting file space %s",fsName);
rc = dsmDeleteFS(dsmHandle,fsName,DSM_REPOS_ALL);
if (rc)
{
   printf("  FAILED!!! ");
   rcApiOut(dsmHandle, rc);
}
else printf("  OK!\n");

Associating a Management Class With Objects

A primary feature of TSM is the use of policy (management classes) to define how objects are stored and managed in TSM storage. A management class is associated with an object when the object is backed up or archived. This management class determines:

Management classes consist of both backup copy groups and archive copy groups. A copy group is a set of attributes that define the management policies for an object that is being backed up or archived. If a backup operation is being performed, the attributes in the backup copy group apply. If an archive operation is being performed, the attributes in the archive copy group apply.

The backup or archive copy group in a particular management class can be empty or NULL. If an object is bound to the NULL backup copy group, that object cannot be backed up. If an object is bound to the NULL archive copy group, the object cannot be archived.

Because the use of policy is a very important component of TSM, the API requires that all objects sent to the server are first assigned a management class by using the dsmBindMC call. The TSM product supports using an Include-Exclude list to affect management class binding. The dsmBindMC call uses the current Include-Exclude list to perform management class binding.

Include statements can associate a specific management class with a backup or archive object. Exclude statements can prevent objects from being backed up but not from being archived. For more information, see Tivoli Storage Manager Installing the Clients.

The API requires that dsmBindMC is called before you back up or archive an object. The dsmBindMC call returns a mcBindKey structure that contains information on management class and copy groups that are associated with the object. Check the copy group destination before proceeding with a send. When you send multiple objects in a single transaction, they must have the same copy group destination. The dsmBindMC function call returns the following information:

Table 11. Information Returned on the dsmBindMC Call

Information Description
Management Class The name of the management class that was bound to the object. The application client can send the dsmBeginQuery call to determine all attributes of this management class.
Backup Copy Group Informs you if a backup copy group exists for this management class. If a backup operation is being performed and a backup copy group does not exist, this object cannot be sent to TSM storage. You will receive an error code if you attempted to send it using the dsmSendObj call.
Backup Copy Destination This field identifies the TSM storage pool to which the data is sent. If you are performing a multiple object backup transaction, all copy destinations within that transaction must be the same. If an object has a different copy destination than previous objects in the transaction, end the current transaction and begin a new transaction before you can send the object. You will receive an error code if you attempt to send objects to different copy destinations within the same transaction.
Archive Copy Group Informs you if an archive copy group exists for this management class. If an archive operation is being performed and an archive copy group does not exist, this object cannot be sent to TSM storage. You will receive an error code if you attempted to send it using the dsmSendObj call.
Archive Copy Destination This field identifies the TSM storage pool to which the data is sent. If you are performing a multiple object archive transaction, all copy destinations within that transaction must be the same. If an object has a different copy destination than previous objects in the transaction, end the current transaction and begin a new transaction before you send the object. You will receive an error code if you attempt to send objects to different copy destinations within the same transaction.

Query Management Classes

Applications can query management classes to determine what management classes are possible for a given node, and to determine what the attributes are within the management class. You can only bind objects to management classes by using the dsmBindMC call. You might want your applications to query the management class attributes and display them to end users. See Querying the TSM System for more information.

In the example in Figure 6, a switch statement is used to distinguish between backup and archive operations when calling dsmBindMC. The information returned from this call is stored in the MCBindKey structure.

Figure 6. An Example of Associating A Management Class With An Object

dsUint16_t     send_type;
dsUint32_t     dsmHandle;
dsmObjName   objName;         /* structure containing the object name  */
mcBindKey    MCBindKey;       /* management class information          */
char         *dest;           /* save destination value                */
 
switch (send_type)
{
   case (Backup_Send) :
      rc = dsmBindMC(dsmHandle,&objName,stBackup,&MCBindKey);
      dest = MCBindKey.backup_copy_dest;
      break;
   case (Archive_Send) :
      rc = dsmBindMC(dsmHandle,&objName,stArchive,&MCBindKey);
      dest = MCBindKey.archive_copy_dest;
      break;
   default : ;
}
 
if (rc)
{
   printf("*** dsmBindMC failed: ");
   rcApiOut(dsmHandle, rc);
   rc = (RC_SESSION_FAILED);
   return;
}

Querying the TSM System

The API has several queries, such as management class query, that applications can use. All queries that use dsmBeginQuery follow the same steps that are described below:

  1. Send the dsmBeginQuery call with the appropriate query type:

    The dsmBeginQuery call informs the API in what format the data is returning from the server. The appropriate fields can be placed in the data structures that are passed by the dsmGetNextQObj calls. The begin query call also permits the application client to set the scope of the query by properly specifying the parameters on the begin query call.

    Note:On the UNIX platform, only the root user can query active backed-up objects (also known as fast path).

  2. Enter the dsmGetNextQObj call to obtain each record from the query. This call passes a buffer that is large enough to hold the data that is returned from the query. Each query type has a corresponding data structure for the data returned. For example, a backup query type has an associated qryRespBackupData structure that is filled in when the dsmGetNextQObj call is sent.

  3. Check the return code. The dsmGetNextQObj call usually returns one of the following codes. You also might receive an error code:

  4. Send the dsmEndQuery call. When all query data is retrieved or additional query data is not needed, enter the dsmEndQuery call to end the query process. This causes the API to flush any remaining data from the query stream and release any resources that were used for the query.

Figure 7 displays the state diagram for performing query operations.

Figure 7. State Diagram for General Queries



REQTEXT


Figure 8 displays the flowchart for performing query operations.

Figure 8. Flowchart for General Queries



REQTEXT


An Example

In the example in Figure 9, a management class query prints out the values of all the fields in the backup and archive copy groups for a particular management class.

Figure 9. An Example of Performing a System Query

dsInt16                rc;
qryMCData            qMCData;
DataBlk              qData;
qryRespMCDetailData  qRespMCData, *mcResp;
char                 *mc, *s;
dsBool_t               done = bFalse;
dsUint32_t               qry_item;
 
/* Fill in the qMCData structure with the query criteria we want */
qMCData.stVersion = qryMCDataVersion;   /* structure version     */
qMCData.mcName    = mc;                 /* management class name */
qMCData.mcDetail  = bTrue;              /* want full details?    */
 
/* Set parameters of the data block used to get or send data     */
qData.stVersion = DataBlkVersion;
qData.bufferLen = sizeof(qryRespMCDetailData);
qData.bufferPtr = (char *)&qRespMCData;
 
qRespMCData.stVersion = qryRespMCDetailDataVersion;
 
if ((rc = dsmBeginQuery(dsmHandle,qtMC,(dsmQueryBuff *)&qMCData)))
{
   printf("*** dsmBeginQuery failed: ");
   rcApiOut(dsmHandle, rc);
   rc = (RC_SESSION_FAILED);
}
 
else
{
   done = bFalse;
   qry_item = 0;
   while (!done)
   {
      rc = dsmGetNextQObj(dsmHandle,&qData);
      if ((   (rc == DSM_RC_MORE_DATA)
           || (rc == DSM_RC_FINISHED))
          && qData.numBytes)
      {
         qry_item++;
         mcResp = (qryRespMCDetailData *)qData.bufferPtr;
         printf("Mgmt. Class %lu:\n",qry_item);
         printf("              Name: %s\n",mcResp->mcName);
         printf("    Backup CG Name: %s\n",mcResp->backupDet.cgName);
            .
            .   /* other fields of backup and archive copy groups */
            .
         printf("     Copy Destination: %s\n",mcResp->archDet.destName);
      }
      else
      {
         done = bTrue;
         if (rc != DSM_RC_FINISHED)
         {
            printf("*** dsmGetNextQObj failed: ");
            rcApiOut(dsmHandle, rc);
         }
      }
      if (rc == DSM_RC_FINISHED) done = bTrue;
   }
   rc = dsmEndQuery(dsmHandle);
}

Sending Data to a Server

The API permits application clients to send data, or named objects and their associated data, to TSM server storage.

Note:You can either back up or archive data. Perform all send operations within a transaction.

The Transaction Model

All data sent to TSM storage during a backup or archive operation is done within a transaction. This provides a high level of data integrity for the TSM product, but it does impose some restrictions that an application client must take into consideration.

Start a transaction by a call to dsmBeginTxn or end a transaction by a call to dsmEndTxn. A single transaction is an atomic action. Data sent within the boundaries of a transaction is either committed to the system at the end of the transaction, or rolled back if the transaction ends prematurely.

Transactions can consist of either single object sends or multiple object sends. Send smaller objects in a multiple object transaction. This greatly improves total system performance, because transaction overhead is decreased. The application client determines whether single or multiple transactions are appropriate.

Send all objects within a multiple object transaction to the same copy destination. If you need to send an object to a different destination than the previous object, end the current transaction and start a new one. Within the new transaction, you can send the object to the new copy destination.

Tivoli Storage Manager limits the number of objects that can be sent in a multiple object transaction. To find this limit, call dsmQuerySessInfo and examine the maxObjPerTxn field. This field displays the value of the TXNGroupmax option that is set on your server.

The application client must keep track of the objects sent within a transaction to perform retry processing or error processing if the transaction ends prematurely. Either the server or the client can stop a transaction at any time. The application client must be prepared to handle sudden transaction ends that it did not start.

File Aggregation

Tivoli Storage Manager servers use a function that is called file aggregation. With file aggregation, all objects sent in a single transaction are stored together, which saves space and improves performance. You can still query and restore the objects separately.

To use this new function, all of the objects in a transaction should have the same filespace name. If the filespace name changes within a transaction, the server closes the existing aggregated object and begins a new one.


Sending Objects to the Server

Application clients can send data, or named objects and their associated data, to TSM storage by using the API backup and archive functions. The backup and archive components of the system permit use of different management procedures for data that is sent to TSM storage.

The size estimate attribute is an estimate of the total size of the data object to send to the server. It is important that you try to be as accurate as possible on this size, because the TSM server uses this attribute for efficient space allocation and object placement within its storage resources. Not specifying this value can result in performance degradation on the server because allocations must be made on a best guess basis.

You can back up or archive objects that are larger than two gigabytes in size. The objects can be either compressed or uncompressed.

To start a send operation, call dsmSendObj. If you have more data than you can send at one time, you can make repeated calls to dsmSendData to transfer the remainder of the information. Call dsmEndSendObj to complete the send operation.

Understand Backup And Archive Objects

The backup component of the TSM system supports several versions of named objects that are stored on the server. Any object backed up to the server that has the same name as an object that is already stored on the server from that client is subject to version control. Objects are considered to be in active or inactive states on the server. The latest copy of an object on the server that has not been deactivated is in the active state. Any other object, whether it is an older version or a deactivated copy, is considered inactive. Management class constructs define different management criteria. They are assigned to active and inactive objects on the server. Backup copy group fields that apply include:

VEREXISTS
The number of inactive versions if active versions exist.

VERDELETED
The number of inactive versions if active versions do not exist.

RETEXTRA
The number of days to keep inactive versions.

RETONLY
The number of days to keep the last inactive versions if active versions do not exist.

If backup versions each have a unique name, such as using a time stamp in the name, then versioning will not happen automatically; every object will be active. Active objects never expire, so an application would be responsible for deactivating these with the dsmDeleteObj call. In this situation, the application would need the deactivated objects to expire as soon as possible. The user would define a backup copy group with VERDELETED=0 and RETONLY=0.

The archive component of the TSM system permits objects to be stored on the server with retention or expiration period controls instead of version control. Each object stored is unique, even though its name might be the same as an object already archived. Archive objects have a description field associated with the meta data that can be used during query to identify a specific object.

Compression

The end user's configuration, along with the dsmSendObj objCompressed flag, determines whether TSM will compress the object during a send. Also, objects with a sizeEstimate less than DSM_MIN_COMPRESS_SIZE will never be compressed.

If the object is compressed already (objCompressed=bTrue), TSM does not try to compress it again. If it is not compressed, TSM decides whether to compress the object, based on the values of the compression option that is set by the TSM administrator and is set in the API configuration sources.

The TSM server administrator can affect compression behavior with the register node command (compression=yes, compression=no, or client-determined). If this is client-determined, then the compression behavior is determined by the option value in the configuration sources.

Some types of data, such as data that is already compressed, might actually get bigger when processed with the compression algorithm. When this happens, the return code DSM_RC_COMPRESS_GREW is generated. If you recognize that this may happen, but want the send operation to continue anyway, tell the end users to specify the following option in their options file:

   COMPRESSAlways Yes
Note:If your application plans to use partial object restore or retrieve, you cannot compress the data while sending it. To enforce this, set ObjAttr.objCompressed to bTrue.

Reading State Diagrams and Flowcharts

The API is designed for straightforward logic flows and clear transitions between the various states of the application client. This clean state transition catches logic flaws and program errors early in the development cycle, greatly enhancing the quality and reliability of the system. For example, you cannot make a dsmSendObj call unless a transaction was started and a dsmBindMC call was previously made for the object that you are backing up.

Figure 10 displays the state diagram for performing backup or archive operations within a transaction. The arrow pointing from "In Send Object" to dsmEndTxn indicates that a dsmEndTxn call can be started after a call to dsmSendObj or dsmSendData. You might want to do do this if an error condition occurred during the send of an object and you want to stop the entire operation. In this case, you must use a vote of DSM_VOTE_ABORT. In normal circumstances, however, call dsmEndSendObj before you end the transaction.

Figure 10. State Diagram for Backup and Archive Operations



REQTEXT


Figure 11 displays the flowchart for performing backup or archive operations within a transaction.

Figure 11. Flowchart for Backup and Archive Operations



REQTEXT


The primary feature in these two diagrams is the loop between the following API calls from within a transaction:

dsmBindMC
dsmSendObj
dsmSendData
dsmEndSendObj

The dsmBindMC call is unique in that you can start it from inside or outside of a transaction boundary. You can also start it from a different transaction, if required. The only requirement for the dsmBindMC call is that it is made prior to backing up or archiving an object. If the object that you are backing up or archiving is not associated with a management class, an error code is returned from dsmSendObj. In this situation, the transaction is ended by calling dsmEndTxn (this error condition is not shown in the flowchart).

The flowchart illustrates how an application would use multiple object transactions. It shows where decision points can be placed to determine if the object that is sent fits within the transaction or whether to start a new transaction.

An Example

Figure 12 demonstrates the use of the API functions that send data to TSM storage. The dsmSendObj call appears inside a switch statement, so that different parameters can be called depending on whether a backup or archive operation is being performed. The dsmSendData call is called from inside a loop that repeatedly sends data until a flag is set that permits the program execution to exit the loop. The entire send operation is performed from within the transaction.

The third parameter on the dsmSendObj call is a buffer that contains the archive description. Because backup objects do not have a description, this parameter is NULL when backing up an object.

Figure 6 displays an example that shows the use of the dsmBindMC function call.

Figure 12. An Example of Sending Data to a Server

if ((rc = dsmBeginTxn(dsmHandle)) )       /* API session handle  */
{
   printf("*** dsmBeginTxn failed: ");
   rcApiOut(dsmHandle, rc);
   return;
}
 
/*  Call dsmBindMC if not done previously */
 
objAttr.sizeEstimate.hi = 0;       /* estimate of        */
objAttr.sizeEstimate.lo = 32000;   /*        object size */
switch (send_type)
{
   case (Backup_Send) :
      rc = dsmSendObj(dsmHandle,stBackup,NULL,&objName,&objAttr,NULL);
      break;
   case (Archive_Send) :
      archData.stVersion = sndArchiveDataVersion;
      archData.descr = desc;
      rc = dsmSendObj(dsmHandle,stArchive,&archData,&objName,&objAttr,NULL);
      break;
   default : ;
}
if (rc)
{
   printf("*** dsmSendObj failed: ");
   rcApiOut(dsmHandle, rc);
   return;
}
 
done = bFalse;
while (!done)
{
   dataBlk.stVersion = DataBlkVersion;
   dataBlk.bufferLen = send_amt;
   dataBlk.numBytes  = 0;
   dataBlk.bufferPtr = bkup_buff;
   rc = dsmSendData(dsmHandle,&dataBlk);
   if (rc)
   {
      printf("*** dsmSendData failed: ");
      rcApiOut(dsmHandle, rc);
      done = bTrue;
   }
   /* Adjust the dataBlk buffer for the next piece to send */
}
  
rc = dsmEndSendObj(dsmHandle);
if (rc)
{
   printf("*** dsmEndSendObj failed: ");
   rcApiOut(dsmHandle, rc);
}
txn_reason = 0;
rc = dsmEndTxn(dsmHandle,           /* API session handle       */
             DSM_VOTE_COMMIT,      /* Commit transaction       */
             &txn_reason);         /* Reason if txn aborted    */
if (rc || txn_reason)
{
   printf("*** dsmEndTxn failed: rc = ");
   rcApiOut(dsmHandle, rc);
   printf("   reason = %u\n",txn_reason);
}

Receiving Data from a Server

Application clients can receive data, or named objects and their associated data, from TSM storage by using the restore and retrieve functions of the product. The restore function accesses objects that previously were backed up, and the retrieve function accesses objects that previously were archived.

Note:The API can only restore or retrieve objects that were backed up or archived using API calls.

Both restore and retrieve functions start with a query operation. The query returns different information depending on whether the data was originally backed up or archived. For instance, a query on backup objects returns information on whether an object is active or inactive, while a query on archive objects returns information such as object descriptions. Both queries return object IDs that TSM uses to uniquely identify the object on the server.

Perform a Partial Object Restore or Retrieve

The application client can receive only a portion of the object. This is called a partial object restore or a partial object retrieve.

Note:A partial object restore or retrieve works only with TSM Version 2 or 3 servers. If your application plans to use a partial object restore or retrieve, you cannot compress the data while sending it. To enforce this, set ObjAttr.objCompressed to bTrue.

To perform a partial object restore or retrieve, associate the following two data fields with each object GetList entry:

offset
The byte offset into the object from which to begin returning data.

length
The number of object bytes to return.

Use DSM_MAX_PARTIAL_GET_OBJ to determine the maximum number of objects that can perform a partial object restore or retrieve.

The following data fields, used on the dsmBeginGetData call, determine what portion of the object is restored or retrieved:

Receive Data With a Restore or Retrieve Procedure

After a query is made and a session is established with the TSM server, the procedure to restore, or retrieve data is to:

  1. Query the TSM server for either backup or archive data.

  2. Determine the objects to restore or retrieve from the server.

  3. Sort the objects on the Restore Order field.

  4. Send the dsmBeginGetData call with the list of objects to access.

  5. Send the dsmGetObj call to obtain each object from the system. Multiple dsmGetData calls might be needed for each object to obtain all associated object data. Send the dsmEndGetObj call after all data for an object is obtained.

  6. Send the dsmEndGetData call after all data for all objects is received, or to end the receive operation.

Query the Server

Before you can begin any restore or retrieve operation, first query the TSM server to determine what objects you can receive from storage. To send the query, the application must enter the proper parameter lists and structures for the dsmBeginQuery call. This includes the file space that the query will examine and pattern-match entries for the high-level and low-level name fields. If the session was initialized with a NULL owner name, it is not necessary to specify the owner field. However, if the session was initialized with an explicit owner name, only objects that explicitly have that owner name associated with them are returned.

The Point-in-time BackupQuery supplies a snapshot of the system at a given time. By specifying a valid date, you can query all files that were backed up to that time. Point-in-time overrides an object state so that, even if an object has an active backup from a later date, the previous inactive copy is returned. An example of this is in pitDate. You must be connected to a Version 3 server to use point-in-time BackupQuery.

A query returns all information that was originally stored with the object, in addition to the following:

copyId
The copyIdHi and copyIdLo values provide an eight-byte number that uniquely identifies this object for this node in TSM storage. Use this ID to request a specific object from storage for restore or retrieve processing.

restoreOrderExt
The restoreOrderExt value provides a mechanism for receiving objects from TSM storage in the most efficient manner possible. Sort the objects to restore on this value to ensure that tapes are mounted only once and are read from front to back.

You must keep some or all of the query information for later processing. Keep the copyId and restoreOrderExt fields because they are needed for the actual restore operation. You must also keep any other information needed to properly open a data file or identify a destination.

Call dsmEndQuery to finish the query operation.

Select Objects to Receive

Once the backup or archive query is performed, the application client must determine which objects, if any, are to be restored or retrieved.

Sort Objects by Restore Order

Once the objects to restore or retrieve are selected, sort them in ascending order (low to high). This sorting is very important to the performance of the restore operation. Sorting the objects on the restoreOrderExt fields ensures that the data is read from the server in the most efficient order. All data on disk is restored first, followed by data on media classes that require volume mounts (such as tape). The restoreOrderExt field also ensures that data on tape is read in order with processing starting at the front of a tape and progressing towards the end.

Properly sorting on the restoreOrderExt field means that duplicate tape mounts and unnecessary tape rewinds do not occur.

Following is an example of sorting objects by using Restore Order fields.

Figure 13. An Example of Sorting Objects With the Restore Order Fields

typedef struct {
dsStruct64_t      objId;
dsUint160_t      restoreOrderExt;
 
}  SortOrder;                /* struct used for sorting */
 
===================================================================
/* the code for sorting starts from here */
dsmQueryType      queryType;
qryBackupData     queryBuffer;
DataBlk           qDataBlkArea;
qryRespBackupData qbDataArea;
dsInt16_t   rc;
dsBool_t  done = bTrue;
int i = 0;
int qry_item;
SortOrder  sortorder[100]; /* sorting can be done up to 100 items
                                             only right now.  Set appropriate
                                             array size to fit your needs */
/*-----------------------------------------------------------------+
| NOTE: Make sure that proper initializations have been done to queryType, 
|       queryBuffer, qDataBlkAre, and qbDataArea.  
|
------------------------------------------------------------------*/
 
   qDataBlkArea.bufferPtf = (char*) &qbDataArea;
 
   rc = dsmBeginQuery(dsmHandle, queryType, (void *) &queryBuffer);
   
   /*----------------------------------------+
   | Make sure to check rc from dsmBeginQuery
   +-----------------------------------------*/
   while (!done)
   {
      rc = dsmGetNextQObj(dsmHandle, &qDataBlkArea);
      if ((rc == DSM_RC_MORE_DATA) ||
          (rc == DSM_RC_FINISHED)) 
           &&( qDataBlkArea.numBytes))
      {
         /******************************************/
         /* transferring restoreOrderExt and objId */
         /******************************************/
         sortorder[i].restoreOrderExt = qbDataArea.restoreOrderExt;
         sortorder[i].objId = qbDataArea.objId;
 
      } /*  if ((rc == DSM_RC_MORE_DATA) || (rc == DSM_RC_FINISHED))  */
      else
      {
          done = bFalse;
          /****************************/
          /* take appropriate action. */
          /****************************/
      } 
     
      i++;
      qry_item++;
 
   } /* while (!done) */
 
   /*****************************************************/
   /* sorting the array using qsort.  After the call,   */
   /* sortorder will be sorted by restoreOrderExt field */ 
   /*****************************************************/
 
   qsort(sortorder, qry_item, sizeof(SortOrder), SortRestoreOrder);
 
 /*-----------------------------------------------------------------+
| NOTE: Make sure to extract sorted object ids and store them in
|       any data structure you want.  
------------------------------------------------------------------*/
 
 
 /*----------------------------------------------------------------+
| int SortRestoreOrder(SortOrder *a, SortOrder *b)
|
| This function compares restoreOrder fields from two structures.
| if (a > b)
|   return(GREATERTHAN);
|| if (a < b)
|   return(LESSTHAN);
|| if (a == b)
|   return(EQUAL);
|+----------------------------------------------------------------*/
int SortRestoreOrder(SortOrder *a, SortOrder *b)
{
    if (a->restoreOrderExt.top > b->restoreOrderExt.top)
       return(GREATERTHAN);
    else if (a->restoreOrderExt.top < b->restoreOrderExt.top)
       return(LESSTHAN);
    else if (a->restoreOrderExt.hi_hi > b->restoreOrderExt.hi_hi)
       return(GREATERTHAN);
    else if (a->restoreOrderExt.hi_hi < b->restoreOrderExt.hi_hi)
       return(LESSTHAN);
    else if (a->restoreOrderExt.hi_lo > b->restoreOrderExt.hi_lo)
       return(GREATERTHAN);
    else if (a->restoreOrderExt.hi_lo < b->restoreOrderExt.hi_lo)
       return(LESSTHAN);
     else if (a->restoreOrderExt.lo_hi > b->restoreOrderExt.lo_hi)
       return(GREATERTHAN);
    else if (a->restoreOrderExt.lo_hi < b->restoreOrderExt.lo_hi)
       return(LESSTHAN);
    else if (a->restoreOrderExt.lo_lo > b->restoreOrderExt.lo_lo)
       return(GREATERTHAN);
    else if (a->restoreOrderExt.lo_lo < b->restoreOrderExt.lo_lo)
       return(LESSTHAN);
    else
       return(EQUAL);
}

Start the dsmBeginGetData Call

Once you select and sort the objects to receive, submit them to TSM for either a restore or retrieve. The dsmBeginGetData call begins a restore or retrieve operation. Complete the information for these two parameters in these calls:

mountWait
This parameter tells the server whether the application client is willing to wait for offline media to be mounted in order to obtain data for an object, or whether that object should be skipped during processing of the restore or retrieve operation.

dsmGetObjListP
This parameter is a data structure that contains a list of all objIds that will be restored or retrieved. Each objId is associated with a partialObjData structure that describes whether the entire objId or only a particular section of the object will be retrieved. l

Each objId is eight bytes in length, so a single restore or retrieve request can contain thousands of objects. The number of objects to request in a single call is limited to DSM_MAX_GET_OBJ or DSM_MAX_PARTIAL_GET_OBJ.

The objects are returned to the application client in the order you requested.

Receive Each Object to Restore or Retrieve

Once the dsmBeginGetData call is sent, perform the following procedure to receive each object that is sent from the server:

  1. Send the dsmGetObj call to identify the object that you requested from the data stream and, to obtain the first block of data that is associated with the object.

  2. Send more dsmGetData calls, as necessary, to obtain the remaining object data.

When you obtain all data for an object, or additional data for the object is needed, you must send a dsmEndGetObj call. If more objects will be received, send the dsmGetObj call again. If you need to stop the process (normally or abnormally), send the dsmEndGetData call.

Start the dsmEndGetData Call

After all data for all requested objects is received, send the dsmEndGetData call. You can also use this call to discard any remaining data in the restore stream for all objects not yet received.

State Diagrams and Flowcharts

Figure 14 displays the state diagram for performing restore or retrieve operations. The arrow pointing from "In Get Object" to dsmEndGetData indicates that you can send a dsmEndGetData call after a call to dsmGetObj or dsmGetData. You might need to do this if an error condition occurred while getting an object from TSM storage and you want to stop the operation. In normal circumstances, however, call dsmEndGetObj first.

Figure 14. State Diagram for Restore and Retrieve Operations



REQTEXT


Figure 15 displays the flowchart for performing restore or retrieve operations.

Figure 15. Flowchart for Restore and Retrieve Operations



REQTEXT


An Example

The example in Figure 16 demonstrates using the API functions to retrieve data from TSM storage. The dsmBeginGetData function call appears inside a switch statement, so that different parameters can be called depending on whether a restore or retrieve operation is being performed. The dsmGetData function call is called from inside a loop that repeatedly gets data from the server until a flag is set that permits the program execution to exit the loop.



Figure 16. An Example of Receiving Data from a Server

/* Call dsmBeginQuery and create a linked list of objects to restore. */
/* Process this list to create the proper list for the GetData calls. */
/* Set up the getList structure to point to this list.                */
/* This example is set up to perform a partial object retrieve.  To   */
/* retrieve only complete objects, set up:                            */
/*       getList.stVersion = dsmGetListVersion;                       */
/*       getList.partialObjData = NULL;                               */
 
dsmGetList getList;
 
getList.stVersion = dsmGetListPORVersion;   /* structure version          */
getList.numObjId  = items;               /* number of items in list       */
getList.objId     = (ObjID *)rest_ibuff; /* list of object IDs to restore */
getList.partialObjData = (PartialObjData *) part_ibuff;
                                         /* list of partial object data   */
switch(get_type)
{
   case (Restore_Get) :
     rc = dsmBeginGetData(dsmHandle,bFalse,gtBackup,&getList);
     break;
   case (Retrieve_Get) :
     rc = dsmBeginGetData(dsmHandle,bFalse,gtArchive,&getList);
     break;
   default : ;
}
if (rc)
{
   printf("*** dsmBeginGetData failed: ");
   rcApiOut(dsmHandle, rc);
   return rc;
}
/* Get each object from the list and verify whether it is on the     */
/* server.  If so, initialize structures with object attributes for  */
/* data validation checks.  When done, call dsmGetObj.               */
 rc = dsmGetObj(dsmHandle,objId,&dataBlk); 
 
 
 
done = bFalse;
while(!done)
{
   if (   (rc == DSM_RC_MORE_DATA)
       || (rc == DSM_RC_FINISHED))
   {
      if (rc == DSM_RC_MORE_DATA)
      {
         dataBlk.numBytes = 0;
         rc = dsmGetData(dsmHandle,&dataBlk);
      }
      else
         done = bTrue;
   }
   else
   {
      printf("*** dsmGetObj or dsmGetData failed: ");
      rcApiOut(dsmHandle, rc);
      done = bTrue;
   }
} /* while */
rc = dsmEndGetObj(dsmHandle);
rc = dsmEndGetData(dsmHandle);
return 0;

Updating Objects on the Server

The API applications can make calls to update objects that were archived (active) or backed up (latest). The dsmUpdateObject function call updates both backed up and archived objects. Use this call in the session state only, updating one object at a time.

To select an archive object, set the dsmSendType function call to stArchive. Only the latest archive object with this assigned name is updated. For an archived object, the application can update the following fields:

To select a backup object, set dsmSendType to stBack. For backed-up objects, only the active copy is updated. For a backed-up object, the application can update the following fields:


Deleting Objects from the Server

API applications can make calls to either delete objects that were archived or turn off objects that were backed up. Deleting archived objects is dependent on the node authorization that was given when the TSM administrator registered the node. Administrators can specify that nodes can delete archived objects. Use the dsmDeleteObj function call to delete archived objects and turn off backup objects.

An archived object is marked for deletion in TSM storage when the system performs its next object expiration cycle. Once you delete an archived object from the server, you cannot retrieve it.

When you turn off a backup object at the server, the object moves from an active state to an inactive state. These states have different retention policies associated with them that are based on the management class that is assigned.

Similar to the dsmSendObj call, a call to dsmDeleteObj is sent within the boundary of a transaction. The state diagram in Figure 10 displays how a call to dsmDeleteObjis preceded by a call to dsmBeginTxn and followed by a call to dsmEndTxn.


Logging Events

An API application can log event messages to central locations. It can direct logging to the TSM server, the local machine, or both. The dsmLogEventEx function call is performed inside a session. To view messages logged on the server, use the query actlog command through the Administrative Client. See the TSM Administrator's Reference for more information.

We recommend that you use the TSM client option, errorlogretention, to prune the client error log file if the application generates numerous client messages that are written to the client log (dsmLogType either logLocal or logBoth).


Putting It All Together

Figure 17 contains the state diagram for the API. It contains all previously displayed state diagrams in addition to several other calls previously not displayed. The points in this diagram include:

Figure 17. Summary State Diagram for the API



REQTEXT


[ Top of Page | Previous Page | Next Page | Table of Contents | Index ]