Method and system for logical-object-to-physical-location translation and physical separation of logical objects6687805Abstract A method and system for providing to a human user or high-level application program a functional interface for translating the names of logical objects into physical mappings of logical objects to physical storage locations within a mass storage device and for allowings a human user or high-level application program to request that two logical objects be physically separated within a mass storage device so that a single failure cannot corrupt both logical objects, the physical separation optionally monitored over time to guarantee that logical objects are not subsequently remapped in a way that results in partial or full overlap. Claims What is claimed is: Description TECHNICAL FIELD
1 class time
2 {
3 public:
4 bool operator==(time);
5 };
An instance of the class "time," defined above, represents a particular time returned, for example, by a call to a system function that returns the current system time. The class "time" may include a number of operator members that allow for comparison of times, subtraction of times, addition of times, and addition of an integer representing some number of units of time, such as seconds, to an instance of the class "time." Only one operator is shown, above.
1 class hostID
2 {
3
4 };
1 class arrayID
2 {
3
4 };
1 class IOaddress
2 {
3
4 };
1 class buffAddress
2 {
3 public:
4 };
An instance of the class "hostID" represents a unique identifier and address for a host computer. An instance of the class "arrayID" represents the address of a disk array, in the current embodiment. Other types of addresses are necessary when the ALOWI resides on another type of mass storage device or on an intermediate computer. An instance of the class "IOaddress" represents the address of electronic data specified in an I/O request for READ or WRITE access. The class "buffAddress" represents the address of a buffer that stores electronic data for transfer between remote computers and the disk array controller.
1 class IO_LUN
2 {
3 public:
4 int getLUN();
5
6 };
1 class IO_LUNs
2 {
3 public:
4 IO_LUN* getFirst();
5 IO_LUN* getNext();
6 };
1 class LUNlist
2 {
3 public:
4 int getFirstLUN();
5 int getNextLUN();
6 void setFirstLUN(int);
7 void setNextLUN(int);
8 void clear();
9 };
An instance of the class "IO_LUN" represents a particular LUN provided by a disk array. The class "I/O_LUN" includes a member function "getLUN" that returns an integer uniquely identifying the LUN described by an intance of I/O_LUN. An instance of the class "I/O_LUNs" represents the collection of LUNs provided by a disk array, and the member functions "getFirst" and "getNext" allow an instance of the class "I/O_LUN" to be retrieved from the collection for each LUN provided by a disk array. An instance of the class "LUNlist" represents a list of integer specifiers of LUNs. The class "LUNlist" includes member functions "getFirstLUN" and "getNextLUN" to get the first integers specifying a LUN from the list and then traverse the remaining integers within the list, and includes analogous functions "setFirstLUN" and "setNextLUN" for inserting integers into the list. The class "LUNlist" includes an additional member function "clear" that clears all entries from the lists. Below, a number of other classes use the same list paradigm, and will not be described in great detail as they are entirely analogous with the member functions of the classes "I/O_LUNs" and "LUNlist."
1 class physicalMediumAddress
2 {
3 public:
4 int getDisk();
5 int getTrack();
6 int getSector();
7 void setDisk(int);
8 void setTrack(int);
9 void setSector(int);
10 };
1 class physicalMediumChunck
2 {
3 public:
4 physicalMediumAddress* getStart();
5 physicalMediumAddress* getEnd();
6 void setStart(physicalMediumAddress*);
7 void setEnd(physicalMediumAddress*);
8 };
1 class chunkList
2
3 public:
4 physicalMediumChunck* getFirstChunk();
5 physicalMediumChunck* getNextChunk();
6 void setFirstChunk(physicalMediumChunck*);
7 void setNextChunk(physicalMediumChunck*);
8 void clear();
9 };
1 class physicalLunTranslation
2 {
3 public:
4 int getLUN();
5 void setLUN(int);
6 chunkList* getPhysical();
7 void setPhysical(chunkList*);
8 };
1 class physicalLunTransList
2 {
3 physicalLunTranslation* getFirstLunTrans();
4 physicalLunTranslation* getNextLunTrans();
5 void setFirstLunTrans(physicalLunTranslation*);
6 void setNextLunTrans(physicalLunTranslation*);
7 void clear();
8 };
An instance of the class "physicalMediumAddress" represents the address of a data entity, such as a byte or word, within a disk array. As described adove, a physical address includes an indication of a disk, a track within the disk, and a sector. The class "physicalMediumAddress" correspondingly includes member funtions for extracting and setting the disk, track, and sector indicators of a physical address. An instance of the class "physicalMediumChunk" describes an extent of data stored within a disk array. An extent of data is a continuous sequence of data entities, such as bytes or words. An extent is characterized by a starting physical location and an ending physical location, and the class "physicalMediumChunk" correspondingly includes member functions for obtaining the start and ending physical address of the chunk and for setting the start and ending physical addresses for the chunk. An instance of the class "chunkList" describes a set of physical extents, or chunks, and employs the same list paradigm as employed by the earlier described classes "IO_LUNs" and "LUNlist." An instance of the class "physicalLunTranslation" describes the translation of a LUN into a list of physical extents, and therefore includes member functions to get and set the LUN, where the LUN is indicated by an integer, and member functions to get and set the physical-location descriptions of the extents contained within an instance of the class "chunkList." An instance of the class "physicalLunTransList" is a list of instances of the class "physicalLunTranslation." An instance of the class "physicalLunTransList" contains member functions that follow the paradigm described earlier for classes "IO_LUNs" and "LUNlists." A list of physical translations represented by an instance of the class "physicalLunTransList" may represent a proposed rearrangement of LUNs to alternative physical locations within a disk array.
1 class objectName
2 {
3 };
1 class objectLunTranslation
2 {
3 public:
4 objectName* getObject();
5 void setObject(objectName*);
6 physicalLunTranslation* getLunTrans();
7 void setLunTrans(physicalLun
Translation*);
8 };
1 class internalArrayMap
2 {
3 public:
4 bool valid(int LUN);
5 physicalLunTranslation* getTrans(int LUN);
6 void setTrans(int LUN, physicalLun
Translation* t);
7 };
An instance of the class "objectName" represents the name of a logical object. An instance of the class "objectLunTranslation" represents the translation of a logical object name to a physical location, and includes member functions to get and set the name of the logical object and member functions to get and set the physical translation corresponding to the logical object. An instance of the class "internalArrayMap" represents an internal map within the disk array that maps the LUNs provided by the disk array to physical locations within a disk array. The class "internalArrayMap" includes the following member functions: (1) "valid," a member function that returns a Boolean value indicating whether or not an integer designating a LUN, provided as an argument, specifies a valid LUN; (2) "getTrans," a member function that provides the physical translation for a LUN specified by an integer provided as an argument; and (3) "setTrans," a member function that enters a physical mapping of a LUN into the internal array map.
1 class IOrequest
2 {
3 public:
4 hostID* getHostID();
5 void setHostID(hostID*);
6 arrayID* getArrayID(arrayID*);
7 void setArrayID();
8 IOCommand getIOCommand();
9 void setIOCommand(IOCommand);
10 int getID();
11 void setID(int);
12 };
1 class DataRequest:public IOrequest
2 {
3 public:
4 int getLUN();
5 void setLUN(int);
6 IOaddress getIOaddress();
7 void setIOaddress();
8 buffAddress getBuffAddress();
9 void setBuffAddress(buffAddress);
10 int getLength();
11 void setLength(int);
12 };
1 class WatchRequest:public IOrequest
2 {
3 public:
4 LUNlist* getLUNlist();
5 void setLUNlist(LUNlist*);
6 int getInterval();
7 void setInterval();
8 };
1 class RearrangeRequest:public IOrequest
2 {
3 public:
4 physicalLunTransList* getTransList();
5 void setTransList (physicalLunTransList*);
6 time getWhen();
7 void setWhen(time t);
8 time getBy();
8 void setBy();
9 };
1 class MoveLunRequest:public IOrequest
2 {
3 public:
4 physicalLunTranslation* getTrans();
5 void setTrans(physicalLunTranslation*);
6 };
1 class TranslateRequest:public IOrequest
2 {
3 public:
4 int getLUN();
5 void setLUN(int);
6 };
1 class IORequestQueue
2 {
3 public:
4 IOrequest* getNext();
5 void queue(IOrequest*);
6 hostID getHeadHost();
7 bool empty();
8 bool terminated();
9 void terminate();
10 };
1 class IORequestQueueArray
2 {
3 public:
4 IORequestQueue* getQ(int);
5 };
The class "IOrequest" encapsulates the various data that together compose an I/O request received by a disk array controller from a remote computer and that is serviced by the disk array controller. The class "IOrequest" includes the following member functions: (1) "getHostID," a function that returns a pointer to an object of the class "HostID" that represents the remote computer that generated the I/O request represented by the current instance of the class "IOrequest;" (2) "setHostID," a member function that sets the host ID of the I/O request represented by the current instance of the class "IOrequest" to the host ID pointed to by the supplied pointer argument; (3) "getArrayID," a member function that returns an address of a disk array to which the I/O request is directed; (4) "setArrayID," a member functions that sets an instance of the class "IOrequest" to be directed to a particular disk array addressed by the address provided as an argument; (5) "getIOCommand," a member function that returns one of the values enumerated in the enumeration "IOCommand" indicating the nature of the I/O request; (6) "setIOCommand," a member function that sets the I/O request to have a type equal to one of the values enumerated in the enumeration "IOCommand" to indicate the nature of the I/O request; (7) "getID," a member function that returns a unique ID identifying an instance of the class "IOrequest;" and (8) "setID," a member function that sets the unique ID identifying the IOrequest. The C++-like pseudocode implementation employs a number of request classes derived from the above-described class "IOrequest." These derived request classes represent particular types of I/O requests. The first derived request class, "DataRequest," represents a standard READ or WRITE I/O command, and includes the following member functions: (1) "getLUN," a member function that returns the LUN to which the I/O request is addressed; (2) "setLUN," a member function that sets the LUN to which the I/O request is addressed; (3) "getIOaddress," a member function that returns the address of the first electronic data to which the I/O request is targeted; (4) "setIOaddress," a member function that sets the address of the first electronic data to which the I/O request is targeted; (5) "getBuffAddress," a member function that returns the address of the buffer that contains data for a WRITE operation or into which data is placed for a READ operation; (6) "setBuffAddress," a member function that sets the address of a buffer that contains data for a WRITE operation or into which data is placed for a READ operation; (7) "getLength," a member function that returns the length, or number of contiguous bytes, words, or blocks of data to be read or written during servicing of the I/O request; and (8) "setLength," a member function that sets the length, or number of contiguous bytes, words, or blocks of data to be read or written during servicing of the I/O request. The next four derived request classes constitute the interface of the ALOWI. These four derived classes stand for the commands, or functions, WATCH, REARRANGE, MOVELUN, AND TRANSLATE. A WATCH command, represented by an instance of the class "WatchRequest," instructs the ALOWI to monitor READ and WRITE activity directed towards LUNs provided within the WATCH command in a list of LUNs for an interval of time provided in the WATCH command as an integer. After monitoring the disk activity directed to the LUNs within the list of LUNs, the ALOWI furnishes, in response to the WATCH command, a proposed physical relocation of some or all of the LUNs in order to optimize disk activity associated with the LUNs. For example, monitoring of the LUNs may determine that greater parallelism can be achieved by separating the LUNs on separate physical disks. In other cases, if access to LUNs appears to be more or less regularly interleaved, the LUNs may be correspondingly interleaved on a single physical disk in order to minimize seek operations within the hard disk drives. An instance of the class "WatchRequest" includes the following member functions: (1) "getLUNlist," a member function that returns a pointer to the list of LUNs included in the WatchRequest; (2) "setLUNlist," a member function that sets the list of LUNs to be watched during execution of the WatchRequest; (3) "getInterval," a member function that extracts from a WatchRequest the time interval during which monitoring should occur; and (4) "setInterval," a member function that sets the time interval for monitoring. An instance of the class "RearrangeRequest" represents a rearrange command that rearranges LUNs within a disk array according to a supplied list of translations of LUNs to sets of physical extents. These sets of physical extents are returned b a disk array controller in response to a WATCH command. Thus, in order to achieve disk array optimization, a WATCH command is directed to the disk array to obtain a proposed list of physical translations represented proposed relocations of LUNs, and that proposed list of changes is supplied to the disk array in a REARRANGE command in order to cause the disk array to remap the LUNs according to the proposed physical translations. An instance of the class "RearrangeRequest" therefore contains the following member functions: (1) "getTransList," a member function that returns a list of proposed locations of LUNs; (2) "setTransList," a member function that sets the request rearrangement to a proposed list of physical translations pointed to by the supplied pointer argument; (3) "getWhen," a member function that returns a time indicating when the rearrangement should begin; (4) "setWhen," a member function that sets the time at which rearrangement should begin for a particular REARRANGE request; (5) "getBy," a member function that returns a time interval during which the rearrangement should occur; and (6) "setBy," a member function that sets the time interval during which the arrangement should occur. An instance of the class "MoveLunRequest" represents a MOVELUN command that directs a disk array to move or relocate a LUN such that the LUN does not overlap any of the disks that include a physical extent specified in an accompanying physical translation. The class "MoveLunRequest" therefore includes member functions to extract and to set a physical LUN translation to indicate both a LUN to relocate and a physical translation away from which the LUN should be relocated. A MOVELUN command is essentially a forced move or forced relation request can be used to physically separate a first LUN from a second LUN. Note that the physical LUN translation included in the MOVELUN request does not represent the physical translation of a LUN, but instead represents the combination of a LUN to forcibly relocate and the physical translation of a second LUN away from which the LUN should be physically relocated. An instance of the class "TranslateRequest" represents a translate command that directs the ALOWI to provide a physical translation of the LUN included in the TranslateRequest. An instance of the class "TranslateRequest" includes member functions to get and set an indication of LUN to which the physical translation is requested. An instance of the class "IORequestQueue" serves as the inQueue (702 in FIG. 7). The class "IORequestQueue" contains the following member functions: (1) "getNext," a member function that dequeues and returns a pointer to the next I/O request on the queue; (2) "queue," a member function that queues an I/O request, pointed to by the single argument, to the queue; (3) "getHeadHost," a member function that returns the hostID from the next I/O request within the queue to be dequeued from the I/O request queue; (4) "empty," a member function that returns a Boolean value indicating whether or not the I/O request queue is empty; (5) "terminated," a member function that returns a Boolean value indicating whether or not the I/O request queue has been terminated, or shut down; and (6) "terminate," a member function that shuts down, or terminates, the I/O request queue. An instance of the class "IORequestQueueArray" maintains a buffer of instances of the class "IORequestQueue" described above. These instances of the class "IORequestQueue" correspond to the IOreqQs (for example, IOreqQ 703 in FIG. 7) associated with threads executing the routine "IOHandler."
1 class IOreply
2 {
3 public:
4 hostID* getHostID();
5 void setHostID(hostID*);
6 arrayID* getArrayID();
7 void setArrayID(arrayID*);
8 IOReplyTp getIOReplyTp();
9 void setIOReplyTp(IOReplyTp);
10 IOstatus getIOStatus();
11 void setIOStatus(IOstatus);
12 int getID();
13 void setID(int);
14 };
1 class DataReply:public IOreply
2 {
3 public:
4 int getLUN();
5 void setLUN(int);
6 IOaddress getIOaddress();
7 void setIOaddress();
8 buffAddress getBuffAddress();
9 void setBuffAddress(buffAddress);
10 int getLength();
11 void setLength(int);
12 };
1 class WatchReply:public IOreply
2 {
3 public:
4 physicalLunTransList* getTransList();
5 void setTransList (physicalLunTrans
List*);
6 };
1 class RearrangeOrMoveReply:public IOreply
2 {
3
4 };
1 class TranslateReply:public IOreply
2 {
3 public:
4 physicalLunTranslation* getTransList();
5 void setTransList (physicalLunTranslation*);
6 };
1 class IOReplyQueue
2 {
3 public:
4 IOreply* getNext();
5 void queue(IOreply*);
6 hostID getHeadHost();
7 bool empty();
8 bool terminated();
9 void terminate();
10 };
An instance of the class "IOreply" represents a reply to an IO command from the disk array back to a host computer. The class "IOreply" includes many of the same member functions included in the class "IOrequest." However, a reply message represented by an instance of the class "IOreply" includes member functions to retrieve and set a reply type rather than the corresponding member functions in the class "IOrequest" that retrieve and set an IO command. The class "IOreply" includes two additional member functions that retrieve and set an IO status that represents the outcome of an IO command executed by the disk array controller. The class "DataReply" represents a reply to a READ or WRITE I/O command, and contains member functions equivalent to those contained in the class "DataRequest." An instance of the class "WatchReply" represents a reply from the disk array controller to a host computer WATCH command, and includes member functions to retrieve and set the physical LUN translation list included in the reply that represents a proposed relocation of one or more LUNs. An instance of the class "RearrangeOrMoveReply" represents the reply from the disk controller to a host computer to deliver a REARRANGE command or a MOVELUN command. In both cases, the status indication in the base class "IOreply" is sufficient to convey needed information from the disk controller back to the host computer. The class "TranslateReply" represents the reply to a TRANSLATE command from the disk controller to the host computer, and includes member functions to retrieve and set a physical translation list that represents the physical translation determined for the LUN specified the TRANSLATE command. Finally, the class "IOReplyQueue" is analogous to the class "IORequestQueue" and is used, for example, for the outQueue (710 in FIG. 7) in the disk array controller. The routine "IORequestHandler" (702 in FIG. 7) represents high-level processing carried out by the disk array controller in order to implement one embodiment of the present invention:
1 void IORequestHandler (IORequestQuueue* inQueue,
2 IOReplyQueue* outQueue,
3 internalArrayMap* map,
4 IO_LUNs* iluns)
5 {
6 IOrequest* iorequest;
7 int LUN;
8 IO_LUN* ilun;
9 IORequestQueueArray IOReqQs;
10 initialize(inQueue, outQueue);
11 ilun = iluns->getFirst();
12 while (ilun != NULL)
13 {
14 LUN = ilun->getLUN();
15 systemStartThread(IOhandler, IOReqQs.getQ(LUN), outQueue);
16 ilun = iluns->getNext();
17 }
18 while (!inQueue->terminated() && !outQueue->terminated())
19 {
20 if (inQueue->empty()) systemWaitOnQueueEvent(inQueue);
21 iorequest = inQueue->getNext();
22 if (iorequest->getIOCommand() == READ .vertline..vertline.
23 iorequest->getIOCommand() == WRITE)
24 {
25 DataRequest* req = reinterpret_cast<DataRequest*>
(iorequest);
26 LUN = req->getLUN();
27 IOReqQs.getQ(LUN)->queue(iorequest);
28 }
29 else if (iorequest->getIOCommand() == WATCH)
30 {
31 WatchRequest* req =
reinterpret_cast<WatchRequest*>(iorequest);
32 WatchReply* rep = new WatchReply;
33 rep->setHostID(req->getHostID());
34 rep->setArrayID(req->getArrayID());
35 rep->setIOReplyTp(WATCH_REPLY);
36 rep->setID(req->getID());
37 systemStartThread(watch, req, rep, map, outQueue);
38 rep = new WatchReply;
39 rep->setHostID(req->getHostID());
40 rep->setArrayID(req->getArrayID());
41 rep->setIOReplyTp(WATCH_REPLY);
42 rep->setID(req->getID());
43 rep->setIOStatus(QUEUED);
44 outQueue->queue(rep);
45 }
46 else if (iorequest->getIOCommand() == REARRANGE)
47 {
48 RearrangeRequest* req =
49 reinterpret_cast<RearrangeRequest*>(iorequest);
50 RearrangeOrMoveReply* rep = new RearrangeOrMoveReply;
51 rep->setHostID(req->getHostID());
52 rep->setArrayID(req->getArrayID());
53 rep->setIOReplyTp(REARRANGE_REPLY);
54 rep->setID(req->getID());
55 systemStartThread(rearrange, req, rep, map, outQueue);
56 rep = new RearrangeOrMoveReply;
57 rep->setHostID(req->getHostID());
58 rep->setArrayID(req->getArrayID());
59 rep->setIOReplyTp(REARRANGE_REPLY);
60 rep->setID(req->getID());
61 rep->setIOStatus(QUEUED);
62 outQueue->queue(rep);
63 }
64 else if (iorequest->getIOCommand() == MOVE)
65 {
66 MoveLunRequest* req =
67 reinterpret_cast<MoveLunRequest*> (iorequest);
68 RearrangeOrMoveReply* rep = new RearrangeOrMoveReply;
69 rep->setHostID(req->getHostID());
70 rep->setArrayID(req->getArrayID());
71 rep->setIOReplyTp(MOVE_REPLY);
72 rep->setID(req->getID());
73 if (LunManager Move (getTrans(), map))
74 rep->setIOStatus(SUCCESS);
75 else rep->setIOStatus(FAILURE);
76 outQueue->queue(rep);
77 delete req;
78 }
79 else if (iorequest->getIOCommand() == Translate)
80 {
81 TranslateRequest* req =
82 reinterpret_cast<TranslateRequest*> (iorequest);
83 TranslateReply* rep = new TranslateReply;
84 rep->setHostID(req->getHostID());
85 rep->setArrayID(req->getArrayID());
86 rep->setIOReplyTp(MOVE_REPLY);
87 rep->setID(req->getID());
88 if (map->valid(req->getLUN()))
89 {
90 rep->setTransList
(map->getTrans(req->getLUN()));
91 rep->setIOStatus(SUCCESS);
92 }
93 else rep->setIOStatus(FAILURE);
94 outQueue->queue(rep);
95 delete req;
96 }
97 }
98 if (!outQueue->terminated())
99 {
100 ilun = iluns->getFirst();
101 LUN = ilun->getLUN();
102 while (ilun = NULL)
103 {
104 IOReqQs.getQ(LUN)->terminate();
105 ilun = iluns->getNext();
106 LUN = ilun->getLUN();
107 }
108 }
109 }
1 void watch (WatchRequest* req, WatchReply* rep,
2 internalArrayMap* map, IOReplyQueue* outQueue)
3 {
4 physicalLunTransList* tlist;
5 tlist = new physicalLunTransList;
6 if (LunManagerWatch(req->getLUNlist(), req->getInterval(),
7 tlist, map))
8 {
9 rep->setTransList(tlist);
10 rep->setIOStatus(SUCCESS);
11 }
12 else rep->setIOStatus(FAILURE);
13 delete req;
14 outQueue->queue(rep);
15 }
1 void rearrange (RearrangeRequest* req, RearrangeOrMoveReply* rep,
2 internalArrayMap* map, IOReplyQueue* outQueue)
3 {
4 systemWaitUntil(req->getWhen());
5 if (LunManagerRearrange(req->getBy(), req->getTransList(),
map))
6 rep->setIOStatus(SUCCESS);
7 else rep->setIOStatus(FAILURE);
8 delete req;
9 outQueue->queue(rep);
10 }
The routine "IORequestHandler" receives pointers to the inQueue (704 in FIG. 7), the outQueue (710 in FIG. 7), a map of the physical locations of all LUNs within the disk array, and a container "iluns" that contains instances of the class "IO_LUN" for each LUN provided by the disk array controller. On line 10, IORequestHandler calls a routine "initialize" to carry out any initialization operations on the I/O queues. These initialization operations are, for the most part, dependent on implementations of other portions of the disk array controller that are beyond the scope of the present invention, and are therefore not described in an implementation of the routine "initialize." On lines 11-17, IORequestHandler starts execution of a separate instance of the routine "IOHandler" for each LUN. The bulk of the processing carried out by IORequestHandler occurs in the loop comprising lines 18-97. This loop is terminated only when one or both of the inQueue and outQueue (704 and 710 in FIG. 7, respectively) are terminated. On line 23, IORequestHandler checks to see if the inQueue is empty and, if so, calls a system function "systemWaitOnQueueEvent" to wait until an I/O request is queued to the inQueue. Once a next I/O request is available for processing, IORequestHandler dequeues that I/O request from the inQueue, on line 21. In the series of if and else-if statements starting in line 22, IORequestHandler processes each type of incoming command. If the incoming command is a READ or WRITE command, as detected by IORequestHandler on lines 22 and 23, then on lines 25-27, IORequestHandler forwards the request to he appropriate IORequestQueue associated with the LUN to which the READ or WRITE command is directed. If, on the other hand, the received I/O command relates to the ALOWI interface, the command is processed in the else-if statements on lines 29-96. If the incoming command is a WATCH command, as detected by IORequestHandler on line 29, then IORequestHandler creates a WatchReply object on line 32 and fills in various fields of the WatchReply object on lines 33-36. On line 37, IORequestHandler starts up a separate thread to execute the routine "Watch," provided below, to carry out monitoring of set of LUNs according to the parameters contained in the WATCH command dequeued from the IORequestQueue. A separate thread is started monitoring may continue for a lengthy period of time. In the meantime, on lines 38-44, IORequestHandler prepares a second WatchReply with an I/O status of "QUEUED" and queues the second WatchReply object to the outQueue to return to the host computer from which the WATCH command was received. If the dequeued I/O command is a REARRANGE command, as detected on line 46 by IORequestHandler, then IORequestHandler carrier out processing similar to that which occurs for a WATCH command, the difference being that a thread is started to execute the routine "rearrange," on line 55, to rearrange a set of LUNs according to a proposed rearrangement provided in the REARRANGE command. If the dequeued I/O request represents a MOVELUN command, as detected by IORequestHandler on line 64, then IORequestHandler prepares a RearrangeOrMoveReply object on line 68, sets various fields of the RearrangeOrMoveReply object on lines 69-72, and then calls the LUN Manager routine "LunManagerMove" on line 73 to forcibly separate a LUN indicated in the physical LUN translation supplied in the MoveRequest from disks that include the physical mapping also supplied in the physical LUN translation in the MOVELUN command, as discussed above. Depending on the outcome of the routine "LunManagerMove," IORequestHandler sets the I/O status of the RearrangeOrMoveReply object to SUCCESS, on line 74, or FAILURE, on line 75, and then queues the RearrangeOrMoveReply to the outQueue for return to the requesting host computer. If the dequeued I/O request represents a TRANSLATE command, as detected by IORequestHandler on line 79, then IORequestHandler extracts a physical translation for a LUN from the internalArrayMap "map" and returns the physical translation to the requesting host computer via the outQueue on line 94. Finally, on lines 98-108, once one or both of the inQueue and outQueue are terminated, IORequestHandler terminates all of the IOreqQ queues and thus terminates all of the I/OHandler threads launched in the while-loop comprising lines 11-17. The routine "watch," provided above, runs asynchronously, using supplied parameters to call the LUN Manager routine "LunManagerWatch," on line 6, in order to carry out the WATCH command. Depending on the outcome of the routine "LunManagerWatch," the routine "watch" sets the I/O status to either SUCCESS, on line 10, or to FAILURE, on line 12, and then queues a WatchReply object to the outQueue before returning to the host computer. The routine "rearrange," also provided above, similarly processes a REARRANGE command by calling the LUN Manager routine "LunManagerRearrange," on line 5. The functional interface provided by the ALOWI to a human user or an application program will next be described in a series of flow-control diagrams. This functional interface comprises the routines "watch," "rearrange," "separateAndWatch," and "physicalLocation." FIG. 8 is a flow-control diagram for the routine "watch." This routine allows a human user or APP on a host computer to request a disk array to monitor activity within the disk array related to a specified logical object and to return a proposed rearrangement of the LUNs to which the logical object is mapped in order to optimize I/O activity directed to the logical object. In step 801, the routine "watch" receives a logical object name, a time interval, and a buffer address as inputs, the time interval argument specifying the time interval during which the disk array should monitor I/O activity directed to the logical object name, and the buffer address argument specifying the place in which the proposed rearrangement information returned by the disk array will be stored. In step 802, the routine "watch" calls ResolveObject functionality currently provided for host computers, to resolve the logical object into a list of one or more LUNs. In step 803, the routine "watch" prepares a WATCH I/O command, using a WatchRequest object provided in the above C++-like pseudocode implementation, and sends the WATCH command to the disk array via an operating-system-supplied communication interface. In step 804, the routine "watch" receives the response to the WATCH command from the disk array. Note that, in this implementation, the routine "watch" blocks during monitoring by the disk array. In the next implementation, to be described below, an asynchronous thread or process is launched in order to carry out an I/O command. An asynchronous paradigm may also be employed in an alternative implementation of the routine "watch." If the WATCH is successfully executed by the disk array, as detected by the routine "watch" in step 805, then the routine "watch" copies the returned physicalLunTransList into the buffer described by the buffer address argument in step 801, sets a return value to TRUE, in step 806, and then returns. Otherwise, in step 807, the routine "watch" sets the return value to FALSE and then returns. FIG. 9 is a flow-control diagram for the routine "rearrange." This routine directs the disk array to rearrange the LUNs to which a logical object is mapped according to a proposed rearrangement returned by the disk array in a preceding call to the function "watch" described above. In step 901, the routine "rearrange" receives a buffer pointer, a first time, a second time, and a callback function pointer as arguments. The buffer pointer points to a proposed rearrangement, residing in a physicalLunTransList, the first time argument indicates the time when the rearrange command is to be processed by the disk array, the second time argument indicates a maximum amount of time the disk array should spend processing the rearrange command, and the callback function pointer points to a function to be called when the rearrangement has been executed. Then, in step 902, the routine "rearrange" launches an asynchronous thread or process, depending on the implementation style, to execute the routine "rearrangement_async," and then returns. FIG. 10 is a flow-control diagram for the routine "rearrange_async." This routine is launched from the previously described routine "rearrange" in step 902. In step 1001, the routine "rearrange_async" receives the arguments passed initially to the routine "rearrange" in step 901 of FIG. 9. In step 1002, the routine "rearrange_async" prepares a RearrangeRequest object using the supplied arguments. In step 1003, the routine "rearrange_async" transmits the REARRANGE command represented by the RearrangeRequest object to the disk array via an operating-system-supplied communications interface. Then, in step 1004, the routine "rearrange_async" waits for, and finally receives, a response from the disk array to the REARRANGE command. If the response contains an I/O status indicating success, as detected by rearrange_async in step 1005, then, in step 1006, rearrange_async calls the callback function, passing to that function a SUCCESS status, and returns. Otherwise, in step 1007, rearrange_async calls the callback function and passes the callback function a FAILURE status and returns. Note that the callback function may, in turn, initiate a number of different events on the host computer to notify either a human user or an APP that the rearrange command has been executed. For example, an email may be sent to a human user, the appearance of an icon on a human user's screen may be altered, a pager number may be dialed and a message transmitted to the pager, or a second callback routine within an APP may be invoked. FIG. 11 is a flow-control diagram for the routine "Separate And Watch." The routine "separateAndWatch" allows a human user or high-level application program to specify the names of two logical objects that the routine then physically separates from one another and subsequently monitors the placement of the logical objects to ensure that the two logical objects remain physically separated. A disk array may constantly remap physical objects, in order to optimize access to the objects, relocate objects around failed disk drives, or for other reasons. Therefore, when two logical objects are separated, their physical locations must be continuously monitored in order to ensure that they are not subsequently remapped partially or fully onto a common disk drive. In step 1101, the routine "separateAndWatch" receives, as arguments, the names of two logical objects to separate as well as a pointer to a callback function. In step 1102, the routine "separateAndWatch" calls the existing ResolveObject functionality on the host computer to translate each logical object name into a list of LUNs onto which the logical object is mapped. In step 1103, the routine "separateAndWatch" calls the routine "TRANSLATE," described below, to translate the list of LUNs to which each logical object has been resolved in step 1102 to lists of physical extents or, in other words, physical translation lists. In step 1104, the two physical translation lists are compared, via a call to the routine "Compare," described below, in order to determine whether the two logical objects overlap. If the two logical objects overlap as detected in step 1105, then the routine "separateAndWatch" prepares and transmits a MOVELUN Request to the disk array on which the logical objects are stored in order to physically separate the logical objects in step 1106. Note that, in a complete implementation, the returned I/O status in the response to the MOVELUN command returned to the routine "separateAndWatch" from the disk array to be checked in step 1106 and, if the returned I/O status is not SUCCESS, then the routine "separateAndWatch" should return an error indication and terminate. This error handling is not explicitly shown in the flow-control diagram of FIG. 11 for the sake of brevity, and because similar error handling has been explicitly shown in previous flow-control diagrams and in the C++-like pseudocode implementation. Finally, in step 1107, the routine "separateAndWatch" calls the routine "monitor," described below, to continuously check that the two logical objects remain physically separated. The routine "monitor" continues to execute asynchronously, while the routine "separateAndWatch" returns following invocation of the routine "monitor." FIG. 12 is a flow-control diagram of the routine "translate." This routine is called from step 1103 of the routine "separateAndWatch." The routine "translate," in step 1201, receives two lists of LUNs that represent the mapping of two logical objects to LUNs within a disk array. In step 1202, the routine "translate" prepares and sends a translate request for the first received list of LUNs to the disk array, and, in step 1203, prepares and sends a translate request to the disk array for the second list of LUNs. In steps 1204 and 1205, the routine "translate" receives the returned physical LUN translations from the disk array in response to the translate request messages sent to the disk array, and stores the returned physical LUN translations for subsequent access by the calling routine. FIG. 13 is a flow-control diagram for the routine "compare." The routine "compare" compares two physical translation lists representing the physical mapping of two logical objects within a disk array in order to determine whether there is any overlap between the physical storage locations of the two logical objects. In step 1301, the routine "compare" receives two physical translation lists as arguments. Steps 1302-1306 together compose two nested while-loops that operate to compare each extent in the first physical translation list with each extent in the second physical translation list. If any of the comparisons indicate an overlap between a physical extent of the first translation list with a physical extent of the second physical translation list, as detected in step 1304, then the routine "compare" returns a value of TRUE. Otherwise, the routine "compare" returns the value FALSE. FIG. 14 is a flow-control diagram for the routine "monitor." This routine is called in step 1107 of the routine "separateAndWatch." The routine "monitor" runs asynchronously, continuously monitoring the physical separation of two logical objects. If, at any point, the routine "monitor" detects that the two logical objects partially or completely physically overlap, then the routine "monitor" notifies either a human user or an APP, via a callback function, to allow the human-user or APP to take appropriate action to either re-separate the logical objects or to otherwise provide for the possibility that both logical objects may be irretrievably corrupted by a single disk failure. In step 1401, the routine "monitor" receives the names of two logical objects and a pointer to a callback function. In step 1402, the routine "monitor" waits for some specific time interval, as it is not essential for the monitoring to run continuously, but only that physical separation of the two logical objects is tracked at regular time intervals. In step 1403, the routine "monitor" calls existing ResolveObject functionality on the host computer to resolve each logical object into a LUN list. In step 1404, the routine "monitor" calls the routine "translate," described above, and in step 1405, the routine "monitor" calls the routine "compare," also described above. The result of calling these two routines is a Boolean value indicating whether or not the two logical objects physically overlap. If the two logical objects physically overlap, as detected in step 1406, then the routine "monitor," in step 1407, calls the callback function in order to alert either a human user or an APP to the detected physical overlap. Otherwise, the routine "monitor" loops back to step 1402. FIG. 15 is a flow-control diagram for the routine "physicalLocation." This routine resolves a logical object name, provided as an argument in step 1501, into a LUN list in step 1502 and then, in step 1503, obtains a physical mapping for the logical object from a disk array via a TRANSLATE command. In step 1504, the routine "physicalLocation" determines whether or not to graphically display the physical translation. If a graphical display is not indicated, then the physical location is returned. Otherwise, a graphical display is prepared in step 1505 and displayed to a human user. FIG. 16 illustrates an example of a graphical display of the mapping of a logical object onto physical disks within a disk array. Although the present invention has been described in terms of a particular embodiment, it is not intended that the invention be limited to this embodiment. Modifications within the spirit of the invention will be apparent to those skilled in the art. For example, an almost limitless number of different types of hardware and software implementations may be used to implement the logical object name translation and logic separation and monitoring functionality provided by the combination of the HLOWI and ALOWI. An almost limitless number of functional interfaces may be provided by the HLOWI and ALOWI that result in the same conceptual functional interfaces provided by the implementations discussed above. Functionality may be moved from the ALOWI to the HLOWI, and vice versa. While the above implementations are related to logical name translation and separation within disk arrays, the same principles can be applied to many different types of mass storage devices. The current invention is not restricted to any particular type of mass storage device. Many different types of design and programming methodologies may be used to accomplish the relatively long-executing monitoring and rearrangement tasks, and many different types of methodologies may be used to return results to a human user or a high-level application program. Processes may launch threads or other processes, which carry out the tasks synchronously, as described above, or processes may simply block, waiting for I/O requests to be executed on a disk array, as also described above. Other paradigms are possible. While the functional interface described above included functions for physically separating and monitoring two logical objects, functions for physically separating and monitoring more than two logical objects are easily implemented in similar fashion, are within the scope of the invention. In the above implementation, callback functions are employed for notification of logical object overlap and other conditions, but shared memory data structures and other techniques may be alternatively employed. The foregoing description, for purposes of explanation, used specific nomenclature to provide a thorough understanding of the invention. However, it will be apparent to one skilled in the art that the specific details are not required in order to practice the invention. The foregoing descriptions of specific embodiments of the present invention are presented for purpose of illustration and description. They are not intended to be exhaustive or to limit the invention to the precise forms disclosed. Obviously many modifications and variations are possible in view of the above teachings. The embodiments are shown and described in order to best explain the principles of the invention and its practical applications, to thereby enable others skilled in the art to best utilize the invention and various embodiments with various modifications as are suited to the particular use contemplated. It is intended that the scope of the invention be defined by the following claims and their equivalents.
|
Same subclass Same class Consider this |
||||||||||
