您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

249 行
10 KiB

  1. // Copyright 2016 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package internal
  15. // This file contains the server implementation of Bytestream declared at:
  16. // https://github.com/googleapis/googleapis/blob/master/google/bytestream/bytestream.proto
  17. //
  18. // Bytestream uses bidirectional streaming (http://grpc.io/docs/guides/concepts.html#bidirectional-streaming-rpc).
  19. import (
  20. "context"
  21. "fmt"
  22. "io"
  23. "google.golang.org/grpc"
  24. "google.golang.org/grpc/codes"
  25. pb "google.golang.org/genproto/googleapis/bytestream"
  26. )
  27. // ReadHandler reads from the Bytestream.
  28. // Note: error returns must return an instance of grpc.rpcError unless otherwise handled in grpc-go/rpc_util.go.
  29. // http://google.golang.org/grpc provides Errorf(code, fmt, ...) to create instances of grpc.rpcError.
  30. // Note: Cancelling the context will abort the stream ("drop the connection"). Consider returning a non-nil error instead.
  31. type ReadHandler interface {
  32. // GetReader provides an io.ReaderAt, which will not be retained by the Server after the pb.ReadRequest.
  33. GetReader(ctx context.Context, name string) (io.ReaderAt, error)
  34. // Close does not have to do anything, but is here for if the io.ReaderAt wants to call Close().
  35. Close(ctx context.Context, name string) error
  36. }
  37. // WriteHandler handles writes from the Bytestream. For example:
  38. // Note: error returns must return an instance of grpc.rpcError unless otherwise handled in grpc-go/rpc_util.go.
  39. // grpc-go/rpc_util.go provides the helper func Errorf(code, fmt, ...) to create instances of grpc.rpcError.
  40. // Note: Cancelling the context will abort the stream ("drop the connection"). Consider returning a non-nil error instead.
  41. type WriteHandler interface {
  42. // GetWriter provides an io.Writer that is ready to write at initOffset.
  43. // The io.Writer will not be retained by the Server after the pb.WriteRequest.
  44. GetWriter(ctx context.Context, name string, initOffset int64) (io.Writer, error)
  45. // Close does not have to do anything, but is related to Server.AllowOverwrite. Or if the io.Writer simply wants a Close() call.
  46. // Close is called when the server receives a pb.WriteRequest with finish_write = true.
  47. // If Server.AllowOverwrite == true then Close() followed by GetWriter() for the same name indicates the name is being overwritten, even if the initOffset is different.
  48. Close(ctx context.Context, name string) error
  49. }
  50. // Internal service that implements pb.ByteStreamServer. Because the methods Write() and Read() are exported for grpc to link against,
  51. // grpcService is deliberately not exported so go code cannot call grpcService.Write() or grpcService.Read().
  52. type grpcService struct {
  53. parent *Server
  54. }
  55. // Server wraps the RPCs in pb. Use bytestream.NewServer() to create a Server.
  56. type Server struct {
  57. status map[string]*pb.QueryWriteStatusResponse
  58. readHandler ReadHandler
  59. writeHandler WriteHandler
  60. rpc *grpcService
  61. // AllowOverwrite controls Server behavior when a WriteRequest with finish_write = true is followed by another WriteRequest.
  62. AllowOverwrite bool
  63. // Bytestream allows a WriteRequest to omit the resource name, in which case it will be appended to the last WriteRequest.
  64. LastWrittenResource string
  65. }
  66. // NewServer creates a new bytestream.Server using gRPC.
  67. // gsrv is the *grpc.Server this bytestream.Server will listen on.
  68. // readHandler handles any incoming pb.ReadRequest or nil which means all pb.ReadRequests will be rejected.
  69. // writeHandler handles any incoming pb.WriteRequest or nil which means all pb.WriteRequests will be rejected.
  70. // readHandler and writeHandler cannot both be nil.
  71. func NewServer(gsrv *grpc.Server, readHandler ReadHandler, writeHandler WriteHandler) (*Server, error) {
  72. if readHandler == nil && writeHandler == nil {
  73. return nil, fmt.Errorf("readHandler and writeHandler cannot both be nil")
  74. }
  75. server := &Server{
  76. status: make(map[string]*pb.QueryWriteStatusResponse),
  77. readHandler: readHandler,
  78. writeHandler: writeHandler,
  79. rpc: &grpcService{},
  80. }
  81. server.rpc.parent = server
  82. // Register a server.
  83. pb.RegisterByteStreamServer(gsrv, server.rpc)
  84. return server, nil
  85. }
  86. // Write handles the pb.ByteStream_WriteServer and sends a pb.WriteResponse
  87. // Implements bytestream.proto "rpc Write(stream WriteRequest) returns (WriteResponse)".
  88. func (rpc *grpcService) Write(stream pb.ByteStream_WriteServer) error {
  89. for {
  90. writeReq, err := stream.Recv()
  91. if err == io.EOF {
  92. // io.EOF errors are a non-error for the Write() caller.
  93. return nil
  94. } else if err != nil {
  95. return grpc.Errorf(codes.Unknown, "stream.Recv() failed: %v", err)
  96. }
  97. if rpc.parent.writeHandler == nil {
  98. return grpc.Errorf(codes.Unimplemented, "instance of NewServer(writeHandler = nil) rejects all writes")
  99. }
  100. status, ok := rpc.parent.status[writeReq.ResourceName]
  101. if !ok {
  102. // writeReq.ResourceName is a new resource name.
  103. if writeReq.ResourceName == "" {
  104. return grpc.Errorf(codes.InvalidArgument, "WriteRequest: empty or missing resource_name")
  105. }
  106. status = &pb.QueryWriteStatusResponse{
  107. CommittedSize: writeReq.WriteOffset,
  108. }
  109. rpc.parent.status[writeReq.ResourceName] = status
  110. } else {
  111. // writeReq.ResourceName has already been seen by this server.
  112. if status.Complete {
  113. if !rpc.parent.AllowOverwrite {
  114. return grpc.Errorf(codes.InvalidArgument, "%q finish_write = true already, got %d byte WriteRequest and Server.AllowOverwrite = false",
  115. writeReq.ResourceName, len(writeReq.Data))
  116. }
  117. // Truncate the resource stream.
  118. status.Complete = false
  119. status.CommittedSize = writeReq.WriteOffset
  120. }
  121. }
  122. if writeReq.WriteOffset != status.CommittedSize {
  123. return grpc.Errorf(codes.FailedPrecondition, "%q write_offset=%d differs from server internal committed_size=%d",
  124. writeReq.ResourceName, writeReq.WriteOffset, status.CommittedSize)
  125. }
  126. // WriteRequest with empty data is ok.
  127. if len(writeReq.Data) != 0 {
  128. writer, err := rpc.parent.writeHandler.GetWriter(stream.Context(), writeReq.ResourceName, status.CommittedSize)
  129. if err != nil {
  130. return grpc.Errorf(codes.Internal, "GetWriter(%q): %v", writeReq.ResourceName, err)
  131. }
  132. wroteLen, err := writer.Write(writeReq.Data)
  133. if err != nil {
  134. return grpc.Errorf(codes.Internal, "Write(%q): %v", writeReq.ResourceName, err)
  135. }
  136. status.CommittedSize += int64(wroteLen)
  137. }
  138. if writeReq.FinishWrite {
  139. r := &pb.WriteResponse{CommittedSize: status.CommittedSize}
  140. // Note: SendAndClose does NOT close the server stream.
  141. if err = stream.SendAndClose(r); err != nil {
  142. return grpc.Errorf(codes.Internal, "stream.SendAndClose(%q, WriteResponse{ %d }): %v", writeReq.ResourceName, status.CommittedSize, err)
  143. }
  144. status.Complete = true
  145. if status.CommittedSize == 0 {
  146. return grpc.Errorf(codes.FailedPrecondition, "writeHandler.Close(%q): 0 bytes written", writeReq.ResourceName)
  147. }
  148. if err = rpc.parent.writeHandler.Close(stream.Context(), writeReq.ResourceName); err != nil {
  149. return grpc.Errorf(codes.Internal, "writeHandler.Close(%q): %v", writeReq.ResourceName, err)
  150. }
  151. }
  152. }
  153. }
  154. // QueryWriteStatus implements bytestream.proto "rpc QueryWriteStatus(QueryWriteStatusRequest) returns (QueryWriteStatusResponse)".
  155. // QueryWriteStatus returns the CommittedSize known to the server.
  156. func (rpc *grpcService) QueryWriteStatus(ctx context.Context, request *pb.QueryWriteStatusRequest) (*pb.QueryWriteStatusResponse, error) {
  157. s, ok := rpc.parent.status[request.ResourceName]
  158. if !ok {
  159. return nil, grpc.Errorf(codes.NotFound, "resource_name not found: QueryWriteStatusRequest %v", request)
  160. }
  161. return s, nil
  162. }
  163. func (rpc *grpcService) readFrom(request *pb.ReadRequest, reader io.ReaderAt, stream pb.ByteStream_ReadServer) error {
  164. limit := int(request.ReadLimit)
  165. if limit < 0 {
  166. return grpc.Errorf(codes.InvalidArgument, "Read(): read_limit=%d is invalid", limit)
  167. }
  168. offset := request.ReadOffset
  169. if offset < 0 {
  170. return grpc.Errorf(codes.InvalidArgument, "Read(): offset=%d is invalid", offset)
  171. }
  172. var buf []byte
  173. if limit > 0 {
  174. buf = make([]byte, limit)
  175. } else {
  176. buf = make([]byte, 1024*1024) // 1M buffer is reasonable.
  177. }
  178. bytesSent := 0
  179. for limit == 0 || bytesSent < limit {
  180. n, err := reader.ReadAt(buf, offset)
  181. if n > 0 {
  182. if err := stream.Send(&pb.ReadResponse{Data: buf[:n]}); err != nil {
  183. return grpc.Errorf(grpc.Code(err), "Send(resourceName=%q offset=%d): %v", request.ResourceName, offset, grpc.ErrorDesc(err))
  184. }
  185. } else if err == nil {
  186. return grpc.Errorf(codes.Internal, "nil error on empty read: io.ReaderAt contract violated")
  187. }
  188. offset += int64(n)
  189. bytesSent += n
  190. if err == io.EOF {
  191. break
  192. }
  193. if err != nil {
  194. return grpc.Errorf(codes.Unknown, "ReadAt(resourceName=%q offset=%d): %v", request.ResourceName, offset, err)
  195. }
  196. }
  197. return nil
  198. }
  199. // Read handles a pb.ReadRequest sending bytes to the pb.ByteStream_ReadServer
  200. // Implements bytestream.proto "rpc Read(ReadRequest) returns (stream ReadResponse)"
  201. func (rpc *grpcService) Read(request *pb.ReadRequest, stream pb.ByteStream_ReadServer) error {
  202. if rpc.parent.readHandler == nil {
  203. return grpc.Errorf(codes.Unimplemented, "instance of NewServer(readHandler = nil) rejects all reads")
  204. }
  205. if request == nil {
  206. return grpc.Errorf(codes.Internal, "Read(ReadRequest == nil)")
  207. }
  208. if request.ResourceName == "" {
  209. return grpc.Errorf(codes.InvalidArgument, "ReadRequest: empty or missing resource_name")
  210. }
  211. reader, err := rpc.parent.readHandler.GetReader(stream.Context(), request.ResourceName)
  212. if err != nil {
  213. return err
  214. }
  215. if err = rpc.readFrom(request, reader, stream); err != nil {
  216. rpc.parent.readHandler.Close(stream.Context(), request.ResourceName)
  217. return err
  218. }
  219. if err = rpc.parent.readHandler.Close(stream.Context(), request.ResourceName); err != nil {
  220. return err
  221. }
  222. return nil
  223. }