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 }