git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/client/object_put_transformer.go (about) 1 package client 2 3 import ( 4 "context" 5 6 buffPool "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/pool" 7 apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" 8 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" 9 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/transformer" 10 "google.golang.org/grpc/codes" 11 "google.golang.org/grpc/status" 12 ) 13 14 func (c *Client) objectPutInitTransformer(prm PrmObjectPutInit) (*objectWriterTransformer, error) { 15 var w objectWriterTransformer 16 w.it = internalTarget{ 17 client: c, 18 prm: prm, 19 } 20 key := &c.prm.Key 21 if prm.Key != nil { 22 key = prm.Key 23 } 24 w.ot = transformer.NewPayloadSizeLimiter(transformer.Params{ 25 Key: key, 26 NextTargetInit: func() transformer.ObjectWriter { return &w.it }, 27 MaxSize: prm.MaxSize, 28 WithoutHomomorphicHash: prm.WithoutHomomorphHash, 29 NetworkState: prm.EpochSource, 30 Pool: prm.Pool, 31 }) 32 return &w, nil 33 } 34 35 type objectWriterTransformer struct { 36 ot transformer.ChunkedObjectWriter 37 it internalTarget 38 err error 39 } 40 41 func (x *objectWriterTransformer) WriteHeader(ctx context.Context, hdr object.Object) bool { 42 x.err = x.ot.WriteHeader(ctx, &hdr) 43 return x.err == nil 44 } 45 46 func (x *objectWriterTransformer) WritePayloadChunk(ctx context.Context, chunk []byte) bool { 47 _, x.err = x.ot.Write(ctx, chunk) 48 return x.err == nil 49 } 50 51 func (x *objectWriterTransformer) Close(ctx context.Context) (*ResObjectPut, error) { 52 if x.err != nil { 53 return nil, x.err 54 } 55 56 ai, err := x.ot.Close(ctx) 57 if err != nil { 58 return nil, err 59 } 60 61 if ai != nil { 62 x.it.res.epoch = ai.Epoch 63 if ai.ParentID != nil { 64 x.it.res.obj = *ai.ParentID 65 } 66 } 67 return x.it.res, nil 68 } 69 70 type internalTarget struct { 71 client *Client 72 res *ResObjectPut 73 prm PrmObjectPutInit 74 useStream bool 75 } 76 77 func (it *internalTarget) WriteObject(ctx context.Context, o *object.Object) error { 78 putSingleImplemented, err := it.tryPutSingle(ctx, o) 79 if putSingleImplemented { 80 return err 81 } 82 it.useStream = true 83 return it.putAsStream(ctx, o) 84 } 85 86 func (it *internalTarget) putAsStream(ctx context.Context, o *object.Object) error { 87 wrt, err := it.client.objectPutInitRaw(ctx, it.prm) 88 if err != nil { 89 return err 90 } 91 if wrt.WriteHeader(ctx, *o) { 92 wrt.WritePayloadChunk(ctx, o.Payload()) 93 } 94 it.res, err = wrt.Close(ctx) 95 if err == nil && it.client.prm.DisableFrostFSErrorResolution && !apistatus.IsSuccessful(it.res.st) { 96 err = apistatus.ErrFromStatus(it.res.st) 97 } 98 return err 99 } 100 101 func (it *internalTarget) tryPutSingle(ctx context.Context, o *object.Object) (bool, error) { 102 if it.useStream { 103 return false, nil 104 } 105 106 prm := PrmObjectPutSingle{ 107 XHeaders: it.prm.XHeaders, 108 BearerToken: it.prm.BearerToken, 109 Session: it.prm.Session, 110 Local: it.prm.Local, 111 CopiesNumber: it.prm.CopiesNumber, 112 Object: o, 113 Key: it.prm.Key, 114 } 115 116 res, err := it.client.ObjectPutSingle(ctx, prm) 117 if err != nil && status.Code(err) == codes.Unimplemented { 118 return false, err 119 } 120 121 if err == nil { 122 it.returnBuffPool(o.Payload()) 123 id, _ := o.ID() 124 it.res = &ResObjectPut{ 125 statusRes: res.statusRes, 126 obj: id, 127 epoch: res.epoch, 128 } 129 if it.client.prm.DisableFrostFSErrorResolution && !apistatus.IsSuccessful(it.res.st) { 130 return true, apistatus.ErrFromStatus(it.res.st) 131 } 132 return true, nil 133 } 134 return true, err 135 } 136 137 func (it *internalTarget) returnBuffPool(playback []byte) { 138 if it.prm.Pool == nil { 139 return 140 } 141 var buffer buffPool.Buffer 142 buffer.Data = playback 143 it.prm.Pool.Put(&buffer) 144 }