![]() |
![]() |
After a query is made and a session is established with the TSM server, the procedure to restore or retrieve data is to:
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. Even if an object has an active backup from a later date, point-in-time overrides an object state so that 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:
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.
Once the backup or archive query is performed, the application client must determine which objects, if any, are to be restored or retrieved.
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 16. 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 = bFalse; |
|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 = bTrue; |
| /****************************/ |
| /* take appropriate action. */ |
| /****************************/ |
| } |
| |
| i++; |
| qry_item++; |
| |
| } /* while (!done) */ |
| rc = dsmEndQuery(dsmHandle); |
| /*check rc */ |
| /*****************************************************/ |
| /* 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); |
|} |
+--------------------------------------------------------------------------------+
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:
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.
Once the dsmBeginGetData call is sent, perform the following procedure to receive each object that is sent from the server:
The DSM_RC_MORE_DATA return code means that a buffer was returned and you should call dsmGetData again. The DSM_RC_FINISHED return code means that the last buffer was returned and you should call dsmEndGetObj again. Check the DataBlk.num Bytes for the actual number of returned bytes.
When you obtain all data for an object, 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.
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. This will flush the data from the server to the client. However, using this method might take time to complete. If you need to end a restore, use dsmTerminate to close the session.