scattergather1&2

Treepobear發表於2020-12-12

系統和專案概覽

這是個網盤軟體。網盤嘛,肯定需要硬體作為storage system,這麼大的storage system不可能只有一臺機器,而是分散的很多臺硬體external host,我們把它們抽象為node。
這整個storage system裡的資料是怎麼組織的呢?以block為單位,每個node裡儲存許多block,這些block的位置是不確定的,但是通過nodeid和blockid可以定位到一個具體的block,這一過程就是gather。

而對使用者來說,需求是上傳、下載或者修改檔案。node、block對於使用者是隱藏的,使用者看到的只有file。因此這個軟體的user application需要一個driver來處理和external hosts(也就是node)相關的所有內容。

user application(準確來說是它的driver)與external hosts之間的資訊互動遵循特定協議,這一協議規定了packet這個格式。第一個assignment的任務就是建立和解析packet。
assignment2的任務是implement呈現給使用者的檔案的開啟和讀寫操作。

使用者根據使用者名稱開啟檔案。driver應當有一個資料結構(起名Vfile吧)記錄檔案資訊,包括它的路徑、控制程式碼、讀寫頭位置、大小、以及每個block的blkid和nodeid。路徑和這個Vfile之間要對應,Vfile和控制程式碼之間也要對應。

sgwrite是scatter操作。driver建立要寫的block包發給node,node返回給driver的包要包含remote nodeid和blockid。driver在Vfile裡把這些資訊記錄下來。

sgread是gather操作。driver發出obtain block的請求,這個請求裡包含了Vfile裡記錄的blockid 和nodeid,因此找得到這個具體的block。返回的包裡包含資料資訊。

Assignment1

建立和驗證包

協議規定包的結構如下:
The ScatterGather Packets
The key to implementing this assignment is to create and process the Packets which are the data regions making up commands and data passed to and from your driver. These regions consist of the following values (in order):

  1. Magic (4 bytes) – this is a special number placed in memory to detect when a packet has been corrupted. This value MUST be SG_MAGIC_VALUE (see sg_defs.h).
  2. Sender Node ID (loc) (8 bytes) – this is an identifier for a sender of a packet. All non-zero values are valid.
  3. Receiver Node ID (rem) (8 bytes) – this is an identifier for a receiver of a packet. All non-zero values are valid.
  4. Block ID (8 bytes) – this is an identifier for block being operated on. All non-zero values are valid.
  5. Operation (4 bytes) – this is the kind of operation being attempted. See a SG_System_OP enumeration in sg_defs.h for information.
  6. Sender sequence number (2 bytes) – this is a unique sequence number for the sender that should be always increasing (that is sent by the sender and incremented by one for each packet). For the purpose of validation in this assignment, you can just check to see if it is non-zero.
  7. Receiver sequence number (2 bytes) – this is a unique sequence number for the receiver reflecting the number of packets sent from that sender to that receiver. For the purpose of validation in this assignment, you can just check to see if it is non-zero.
  8. Data indicator (1 byte) – this indicates whether the packet contains a data block. 0 means that it does not, and 1 means that it does (you can assume this is always 0 or 1 for the unit test cases).
  9. Data (SG_BLOCK_SIZE bytes) – this is the data block associated with the packet, if needed. This will be added to the packet of the data indicator=1 only.
  10. Magic (4 bytes) – this is a special number placed in memory to detect when a packet has been corrupted. This value MUST be SG_MAGIC_VALUE (see sg_defs.h).
    Here is a picture of what the buffer should look like.
    在這裡插入圖片描述
    給定的函式結構:
SG_Packet_Status serialize_sg_packet( SG_Node_ID loc, SG_Node_ID rem, SG_Block_ID blk, SG_System_OP op, SG_SeqNum sseq, SG_SeqNum rseq, char *data, char *packet, size_t *plen );
  • loc, rem, blk, op, sseq, rseq – are as defined below
  • data – this is a pointer to the data for the block, or NULL if no data to be processed
  • packet – this is a buffer where you can create the packet.
  • plen – the this is a pointer to a variable containing the length of the packet. Note you will need to re-assign the value at this pointer to the length of the packet you created.
SG_Packet_Status deserialize_sg_packet( SG_Node_ID *loc, SG_Node_ID *rem, SG_Block_ID *blk, SG_System_OP *op, SG_SeqNum *sseq, SG_SeqNum *rseq, char *data, char *packet, size_t plen );

提交併驗證成功的程式碼:
難度不大,主要是memcpy函式的使用。



//
// Function     : serialize_sg_packet
// Description  : Serialize a ScatterGather packet (create packet)
//
// Inputs       : loc - the local node identifier
//                rem - the remote node identifier
//                blk - the block identifier
//                op - the operation performed/to be performed on block
//                sseq - the sender sequence number
//                rseq - the receiver sequence number
//                data - the data block (of size SG_BLOCK_SIZE) or NULL
//                packet - the buffer to place the data
//                plen - the packet length (int bytes)
// Outputs      : 0 if successfully created, -1 if failure

SG_Packet_Status serialize_sg_packet( SG_Node_ID loc, SG_Node_ID rem, SG_Block_ID blk,
        SG_System_OP op, SG_SeqNum sseq, SG_SeqNum rseq, char *data,
        char *packet, size_t *plen ) {

    //The return value, initialized with OK
    SG_Packet_Status result = SG_PACKT_OK;
    
    ///check local node id
    if(loc == 0){
        result = SG_PACKT_LOCID_BAD;
        return result;
    }
    ///check receiver node id
    if(rem == 0){
        result = SG_PACKT_REMID_BAD;
        return result;
    }
    ///check Block ID
    if(blk==0){
        result = SG_PACKT_BLKID_BAD;
        return result;
    }
    ///check Operation
    if(op<SG_INIT_ENDPOINT||op>SG_MAXVAL_OP){
        result = SG_PACKT_OPERN_BAD;
        return result;
    }
    ///check Sender sequence number
    if(sseq == 0){
        result = SG_PACKT_SNDSQ_BAD;
        return result;
    }
    ///check Receiver sequence number
    if(rseq == 0){
        result = SG_PACKT_RCVSQ_BAD;
        return result;
    }
    
    //create packet
    if(data == NULL){

        *plen=41;
        uint64_t temp = SG_MAGIC_VALUE;
        memcpy(packet,&temp, 4);
        temp = loc;
        memcpy(packet+4,&temp, 8);
        temp = rem;
        memcpy(packet+12,&temp, 8);
        temp = blk;
        memcpy(packet+20, &temp, 8);
        temp = op;
        memcpy(packet+28,&temp, 4);
        temp =sseq;
        memcpy(packet+32,&temp, 2);
        temp = rseq;
        memcpy(packet+34,&temp, 2);
        temp = 0;
        memcpy(packet+36,&temp, 1);
        temp = SG_MAGIC_VALUE;
        memcpy(packet+37,&temp, 4);
        
    }else{

        *plen=41+SG_BLOCK_SIZE;
        uint64_t temp = SG_MAGIC_VALUE;
        memcpy(packet,&temp, 4);
        temp = loc;
        memcpy(packet+4,&temp, 8);
        temp = rem;
        memcpy(packet+12,&temp, 8);
        temp = blk;
        memcpy(packet+20, &temp, 8);
        temp = op;
        memcpy(packet+28,&temp, 4);
        temp =sseq;
        memcpy(packet+32,&temp, 2);
        temp = rseq;
        memcpy(packet+34,&temp, 2);
        temp = 1;
        memcpy(packet+36,&temp, 1);
        
        memcpy(packet+37,data,SG_BLOCK_SIZE);
        temp = SG_MAGIC_VALUE;
        memcpy(packet+37+SG_BLOCK_SIZE,&temp,4);
    }
    
    return(result);
}


//
// Function     : deserialize_sg_packet
// Description  : De-serialize a ScatterGather packet (unpack packet)
//
// Inputs       : loc - the local node identifier
//                rem - the remote node identifier
//                blk - the block identifier
//                op - the operation performed/to be performed on block
//                sseq - the sender sequence number
//                rseq - the receiver sequence number
//                data - the data block (of size SG_BLOCK_SIZE) or NULL
//                packet - the buffer to place the data
//                plen - the packet length (int bytes)
// Outputs      : 0 if successfully created, -1 if failure

SG_Packet_Status deserialize_sg_packet( SG_Node_ID *loc, SG_Node_ID *rem, SG_Block_ID *blk,
        SG_System_OP *op, SG_SeqNum *sseq, SG_SeqNum *rseq, char *data,
        char *packet, size_t plen ) {

    //The return value, initialized with OK
    SG_Packet_Status result = SG_PACKT_OK;
    
    //check packet length
    if(!(plen==41||plen==(41+SG_BLOCK_SIZE))){
        result = SG_PACKT_PDATA_BAD;
        return result;
    }
    
    //check head magic number
    uint32_t temp=0;
    memcpy(&temp, packet, 4);
    if(temp!=SG_MAGIC_VALUE){
        result = SG_PACKT_PDATA_BAD;
        return result;
    }
    
    //get the value
    memcpy(loc, packet+4, 8);
    if(*loc==0){
        result = SG_PACKT_LOCID_BAD;
        return result;
    }
    memcpy(rem, packet+12, 8);
    if(*rem==0){
        result = SG_PACKT_REMID_BAD;
        return result;
    }
    memcpy(blk, packet+20, 8);
    if(*blk==0){
        result = SG_PACKT_BLKID_BAD;
        return result;
    }
    memcpy(op, packet+28, 4);
    if(*op>SG_MAXVAL_OP||*op<SG_INIT_ENDPOINT){
        result = SG_PACKT_OPERN_BAD;
        return result;
    }
    memcpy(sseq, packet+32, 2);
    if(*sseq==0){
        result = SG_PACKT_SNDSQ_BAD;
        return result;
    }
    memcpy(rseq, packet+34, 2);
    if(*rseq==0){
        result = SG_PACKT_RCVSQ_BAD;
        return result;
    }

    //check data and get data
    char data_indicator;
    memcpy(&data_indicator, packet+36, 1);
    if(data_indicator==0){
        memcpy(&temp, packet+37, 4);
        if(temp!=SG_MAGIC_VALUE){
            result = SG_PACKT_PDATA_BAD;
            return result;
        }
        data = NULL;
    }else{
        memcpy(&temp, packet+37, 4);
        if(temp==SG_MAGIC_VALUE){
            result = SG_PACKT_BLKDT_BAD;
            return result;
        }
        memcpy(&temp, packet+37+SG_BLOCK_SIZE, 4);
        if(temp!=SG_MAGIC_VALUE){
            result = SG_PACKT_BLKLN_BAD;
            return result;
        }
        memcpy(data, packet+37, SG_BLOCK_SIZE);
    }
    
    return(result);
}

Assignment2

Vfile的結構以及Vfile、fh、path之間的對應關係:

#define SG_MAX_FH 1000  //使用者最多可以儲存的檔案個數

typedef struct{
    char* path;
    SgFHandle fh;
    int pos;
    int size;
    SG_Node_ID nid[20];
    SG_Block_ID blkid[20];
}Vfile;

// Global Data 記錄對應關係
SgFHandle fhTable[SG_MAX_FH];
Vfile* vfTable[SG_MAX_FH];
char* pathTable[SG_MAX_FH];

不同operation傳送的資料包遵循以下格式:
在這裡插入圖片描述

sgInitEndpoint()


//
// Function     : sgInitEndpoint
// Description  : Initialize the endpoint
//
// Inputs       : none
// Outputs      : 0 if successfull, -1 if failure

int sgInitEndpoint( void ) {

    // Local variables
    char initPacket[SG_BASE_PACKET_SIZE], recvPacket[SG_BASE_PACKET_SIZE];
    size_t pktlen, rpktlen;
    SG_Node_ID loc, rem;
    SG_Block_ID blkid;
    SG_SeqNum sloc, srem;
    SG_System_OP op;
    SG_Packet_Status ret;

    // Local and do some initial setup
    logMessage( LOG_INFO_LEVEL, "Initializing local endpoint ..." );
    sgLocalSeqno = SG_INITIAL_SEQNO;

    // Setup the packet
    pktlen = SG_BASE_PACKET_SIZE;
    if ( (ret = serialize_sg_packet( SG_NODE_UNKNOWN, // Local ID
                                    SG_NODE_UNKNOWN,   // Remote ID
                                    SG_BLOCK_UNKNOWN,  // Block ID
                                    SG_INIT_ENDPOINT,  // Operation
                                    sgLocalSeqno++,    // Sender sequence number
                                    SG_SEQNO_UNKNOWN,  // Receiver sequence number
                                    NULL, initPacket, &pktlen)) != SG_PACKT_OK ) {
        logMessage( LOG_ERROR_LEVEL, "sgInitEndpoint: failed serialization of packet [%d].", ret );
        return( -1 );
    }

    // Send the packet
    rpktlen = SG_BASE_PACKET_SIZE;
    if ( sgServicePost(initPacket, &pktlen, recvPacket, &rpktlen) ) {
        logMessage( LOG_ERROR_LEVEL, "sgInitEndpoint: failed packet post" );
        return( -1 );
    }

    // Unpack the recieived data
    if ( (ret = deserialize_sg_packet(&loc, &rem, &blkid, &op, &sloc,
                                    &srem, NULL, recvPacket, rpktlen)) != SG_PACKT_OK ) {
        logMessage( LOG_ERROR_LEVEL, "sgInitEndpoint: failed deserialization of packet [%d]", ret );
        return( -1 );
    }

    // Sanity check the return value
    if ( loc == SG_NODE_UNKNOWN ) {
        logMessage( LOG_ERROR_LEVEL, "sgInitEndpoint: bad local ID returned [%ul]", loc );
        return( -1 );
    }

    // Set the local node ID, log and return successfully
    sgLocalNodeId = loc;
    logMessage( LOG_INFO_LEVEL, "Completed initialization of node (local node ID %lu", sgLocalNodeId );
    return( 0 );
}

sgopen()


//
// Function     : sgopen
// Description  : Open the file for for reading and writing
//
// Inputs       : path - the path/filename of the file to be read
// Outputs      : file handle if successful test, -1 if failure

SgFHandle sgopen(const char *path) {

    // First check to see if we have been initialized
    if (!sgDriverInitialized) {

        // Call the endpoint initialization
        if ( sgInitEndpoint() ) {
            logMessage( LOG_ERROR_LEVEL, "sgopen: Scatter/Gather endpoint initialization failed." );
            return( -1 );
        }

        // Set to initialized
        sgDriverInitialized = 1;
    }

// FILL IN THE REST OF THE CODE

    SgFHandle fh=-1;
    int i=0;
    for(i=0;i<SG_MAX_FH;i++){
        if(pathTable[i]==path){
            fh=fhTable[i];
            break;
        }
    }
    if(i!=SG_MAX_FH){
        return fh;
    }
    else{
        
        fh = rand()%SG_MAX_FH;
        int flag = 0;
        while(!flag){
            for(i=0;i<SG_MAX_FH;i++){
                if(fhTable[i]==0){
                    flag = 1;
                    fhTable[i]=fh;
                    break;
                }
                else if(fhTable[i]==fh){
                    fh=rand()%1000;
                    break;
                }
            }
        }
        
        Vfile *newf=malloc(sizeof(Vfile));
        newf->fh=fh;
        newf->path = path;
        newf->pos=0;
        newf->size=0;
        for(int j=0;j<20;j++){
            newf->blkid[j]=0;
            newf->nid[j]=0;
        }
        vfTable[i]=newf;
        pathTable[i]=path;
    }
    
    // Return the file handle
    return( fh );
}

sgwrite()


//
// Function     : sgwrite
// Description  : write data to the file
//
// Inputs       : fh - file handle for the file to write to
//                buf - pointer to data to write
//                len - the length of the write
// Outputs      : number of bytes written if successful test, -1 if failure

int sgwrite(SgFHandle fh, char *buf, size_t len) {

    int i=0;
    for(i=0;i<SG_MAX_FH;i++){
        if(fhTable[i]==0) return -1;
        if(fhTable[i]==fh) break;
    }
    Vfile *vf = vfTable[i];
    
    vf->pos=vf->size; //讀寫頭一定要在檔案尾端
    
    char createPacket[SG_DATA_PACKET_SIZE],recvPacket[SG_BASE_PACKET_SIZE];
    size_t pktlen,rpktlen;
    SG_Packet_Status ret;
    SG_Block_ID blkid;
    SG_System_OP op;
    SG_Node_ID loc = sgLocalNodeId,rem;
    SG_SeqNum sloc = sgLocalSeqno++,srem;
    
    // Setup the packet
    pktlen = SG_DATA_PACKET_SIZE;
    if ( (ret = serialize_sg_packet( loc, // Local ID
                                    SG_NODE_UNKNOWN,   // Remote ID
                                    SG_BLOCK_UNKNOWN,  // Block ID
                                    SG_CREATE_BLOCK,  // Operation
                                    sloc,   //local sequence number
                                    SG_SEQNO_UNKNOWN,
                                    buf, createPacket, &pktlen)) != SG_PACKT_OK ) {
        logMessage( LOG_ERROR_LEVEL, "sgwrite: failed serialization of packet [%d].", ret );
        return( -1 );
    }
    
    // Send the packet
    rpktlen = SG_BASE_PACKET_SIZE;
    if ( sgServicePost(createPacket, &pktlen, recvPacket, &rpktlen) ) {
        logMessage( LOG_ERROR_LEVEL, "sgwrite: failed packet post" );
        return( -1 );
    }
    
    // Unpack the recieived data
    if ( (ret = deserialize_sg_packet(&loc, &rem, &blkid, &op, &sloc,
                                    &srem, NULL, recvPacket, rpktlen)) != SG_PACKT_OK ) {
        logMessage( LOG_ERROR_LEVEL, "sgwrite: failed deserialization of packet [%d]", ret );
        return( -1 );
    }
    
    vf->blkid[vf->pos] = blkid;
    vf->nid[vf->pos] = rem;
    vf->pos++;
    vf->size++;
    
    // Log the write, return bytes written
    return( len );
}

sgseek()


//
// Function     : sgseek
// Description  : Seek to a specific place in the file
//
// Inputs       : fh - the file handle of the file to seek in
//                off - offset within the file to seek to
// Outputs      : new position if successful, -1 if failure

int sgseek(SgFHandle fh, size_t off) {
    int i=0;
    for(i;i<SG_MAX_FH;i++){
        if(fhTable[i]==0) return -1;
        if(fhTable[i]==fh) break;
    }
    Vfile *vf = vfTable[i];
    
    if(vf->size*SG_BLOCK_SIZE<off){
        return -1;
    }
    
     vf->pos = (int)off/SG_BLOCK_SIZE;
       
       // Return new position
       return(vf->pos*SG_BLOCK_SIZE);
}

sgread()


//
// Function     : sgread
// Description  : Read data from the file
//
// Inputs       : fh - file handle for the file to read from
//                buf - place to put the data
//                len - the length of the read
// Outputs      : number of bytes read, -1 if failure

int sgread(SgFHandle fh, char *buf, size_t len) {

    int i=0;
    for(i=0;i<SG_MAX_FH;i++){
        if(fhTable[i]==0) return -1;
        if(fhTable[i]==fh) break;
    }
    Vfile *vf = vfTable[i];
    if(vf->pos==vf->size) return -1;
    
    SG_Block_ID blkid;
    blkid = vf->blkid[vf->pos];
    char sendPacket[SG_BASE_PACKET_SIZE],recvPacket[SG_DATA_PACKET_SIZE];
    size_t pktlen,rpktlen;
    SG_Packet_Status ret;
    SG_System_OP op;
    SG_Node_ID loc = sgLocalNodeId,rem = vf->nid[vf->pos];
    SG_SeqNum sloc = sgLocalSeqno++,srem;
    
    // Setup the packet
    pktlen = SG_BASE_PACKET_SIZE;
    if ( (ret = serialize_sg_packet(loc, // Local ID
                                    rem,   // Remote ID
                                    blkid,  // Block ID
                                    SG_OBTAIN_BLOCK,  // Operation
                                    sloc,   //local sequence number
                                    SG_SEQNO_UNKNOWN,
                                    buf, sendPacket, &pktlen)) != SG_PACKT_OK ) {
        logMessage( LOG_ERROR_LEVEL, "sgread: failed serialization of packet [%d].", ret );
        return( -1 );
    }
    
    // Send the packet
    rpktlen = SG_DATA_PACKET_SIZE;
    if ( sgServicePost(sendPacket, &pktlen, recvPacket, &rpktlen) ) {
        logMessage( LOG_ERROR_LEVEL, "sgread: failed packet post" );
        return( -1 );
    }
    
    // Unpack the recieived data
    if ( (ret = deserialize_sg_packet(&loc, &rem, &blkid, &op, &sloc,
                                    &srem, buf, recvPacket, rpktlen)) != SG_PACKT_OK ) {
        logMessage( LOG_ERROR_LEVEL, "sgread: failed deserialization of packet [%d]", ret );
        return( -1 );
    }
    
    vf->pos += len/SG_BLOCK_SIZE;
    // Return the bytes processed
    return( len );
}

sgclose()


//
// Function     : sgclose
// Description  : Close the file
//
// Inputs       : fh - the file handle of the file to close
// Outputs      : 0 if successful test, -1 if failure

int sgclose(SgFHandle fh) {

    int i;
    for(i=0;i<SG_MAX_FH;i++){
        if(fhTable[i]==0) return -1;
        if(fhTable[i]==fh) break;
    }
    
    int j;
    for(j=0;j<SG_MAX_FH;j++){
        if(fhTable[j]==0){
            fhTable[i]=fhTable[j-1];
            fhTable[j]=0;
            break;
        }
    }
    
    pathTable[i]=pathTable[j-1];
    pathTable[j]=NULL;
    vfTable[i]=vfTable[j-1];
    vfTable[j]=NULL;
    
    // Return successfully
    return( 0 );
}

sgshutdown()


//
// Function     : sgshutdown
// Description  : Shut down the filesystem
//
// Inputs       : none
// Outputs      : 0 if successful test, -1 if failure

int sgshutdown(void) {

    for(int i=0;i<SG_MAX_FH;i++){
        fhTable[i]=0;
        vfTable[i]=NULL;
        pathTable[i]=NULL;
    }
    // Log, return successfully
    logMessage( LOG_INFO_LEVEL, "Shut down Scatter/Gather driver." );
    return( 0 );
}