github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/objectserver/rpcd/getObjects.go (about)

     1  package rpcd
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  	"sync"
     8  
     9  	"github.com/Cloud-Foundations/Dominator/lib/hash"
    10  	"github.com/Cloud-Foundations/Dominator/lib/srpc"
    11  	"github.com/Cloud-Foundations/Dominator/proto/objectserver"
    12  )
    13  
    14  var exclusive sync.RWMutex
    15  
    16  func (objSrv *srpcType) GetObjects(conn *srpc.Conn) error {
    17  	defer conn.Flush()
    18  	var request objectserver.GetObjectsRequest
    19  	var response objectserver.GetObjectsResponse
    20  	if request.Exclusive {
    21  		exclusive.Lock()
    22  		defer exclusive.Unlock()
    23  	} else {
    24  		exclusive.RLock()
    25  		defer exclusive.RUnlock()
    26  		objSrv.getSemaphore <- true
    27  		defer releaseSemaphore(objSrv.getSemaphore)
    28  	}
    29  	var err error
    30  	if err = conn.Decode(&request); err != nil {
    31  		response.ResponseString = err.Error()
    32  		return conn.Encode(response)
    33  	}
    34  	response.ObjectSizes, err = objSrv.objectServer.CheckObjects(request.Hashes)
    35  	if err != nil {
    36  		response.ResponseString = err.Error()
    37  		return conn.Encode(response)
    38  	}
    39  	// First a quick check for existence. If any objects missing, fail request.
    40  	var firstMissingObject *hash.Hash
    41  	numMissingObjects := 0
    42  	for index, hashVal := range request.Hashes {
    43  		if response.ObjectSizes[index] < 1 {
    44  			firstMissingObject = &hashVal
    45  			numMissingObjects++
    46  		}
    47  	}
    48  	if firstMissingObject != nil {
    49  		if numMissingObjects == 1 {
    50  			response.ResponseString = fmt.Sprintf("unknown object: %x",
    51  				*firstMissingObject)
    52  		} else {
    53  			response.ResponseString = fmt.Sprintf(
    54  				"first of %d unknown objects: %x", numMissingObjects,
    55  				*firstMissingObject)
    56  		}
    57  		return conn.Encode(response)
    58  	}
    59  	objectsReader, err := objSrv.objectServer.GetObjects(request.Hashes)
    60  	if err != nil {
    61  		response.ResponseString = err.Error()
    62  		return conn.Encode(response)
    63  	}
    64  	defer objectsReader.Close()
    65  	if err := conn.Encode(response); err != nil {
    66  		return err
    67  	}
    68  	conn.Flush()
    69  	buffer := make([]byte, 32<<10)
    70  	for _, hashVal := range request.Hashes {
    71  		length, reader, err := objectsReader.NextObject()
    72  		if err != nil {
    73  			objSrv.logger.Println(err)
    74  			return err
    75  		}
    76  		nCopied, err := io.CopyBuffer(conn, reader, buffer)
    77  		reader.Close()
    78  		if err != nil {
    79  			objSrv.logger.Printf("Error copying: %s\n", err)
    80  			return err
    81  		}
    82  		if nCopied != int64(length) {
    83  			txt := fmt.Sprintf("Expected length: %d, got: %d for: %x",
    84  				length, nCopied, hashVal)
    85  			objSrv.logger.Printf(txt)
    86  			return errors.New(txt)
    87  		}
    88  	}
    89  	objSrv.logger.Debugf(0, "GetObjects() sent: %d objects\n",
    90  		len(request.Hashes))
    91  	return nil
    92  }
    93  
    94  func releaseSemaphore(semaphore <-chan bool) {
    95  	<-semaphore
    96  }