@@ -58,7 +58,8 @@ func (w *gRPCWriter) Write(p []byte) (n int, err error) {
5858 // Skip checksum calculation if user configures MD5 or CRC32C themselves.
5959 if ! w .disableAutoChecksum &&
6060 ! w .sendCRC32C &&
61- ! md5Provided {
61+ ! md5Provided &&
62+ ! w .append {
6263 w .fullObjectChecksum = crc32 .Update (w .fullObjectChecksum , crc32cTable , p )
6364 }
6465 // write command successfully delivered to sender. We no longer own cmd.
@@ -109,6 +110,11 @@ func (w *gRPCWriter) CloseWithError(err error) error {
109110 return nil
110111}
111112
113+ func (w * gRPCWriter ) setAppendFinalCRC32C (sendAppendFinalCRC32C bool , c uint32 ) {
114+ w .sendAppendFinalCRC32C = sendAppendFinalCRC32C
115+ w .appendFinalCRC32C = c
116+ }
117+
112118func (c * grpcStorageClient ) OpenWriter (params * openWriterParams , opts ... storageOption ) (internalWriter , error ) {
113119 if params .attrs .Retention != nil {
114120 // TO-DO: remove once ObjectRetention is available - see b/308194853
@@ -259,7 +265,9 @@ type gRPCWriter struct {
259265 setSize func (int64 )
260266 setTakeoverOffset func (int64 )
261267
262- fullObjectChecksum uint32
268+ fullObjectChecksum uint32
269+ appendFinalCRC32C uint32
270+ sendAppendFinalCRC32C bool
263271
264272 flushSupported bool
265273 sendCRC32C bool
@@ -948,9 +956,9 @@ type getObjectChecksumsParams struct {
948956 sendCRC32C bool
949957 disableAutoChecksum bool
950958 objectAttrs * ObjectAttrs
951- fullObjectChecksum func () uint32
959+ fullObjectChecksum func () * uint32
952960 finishWrite bool
953- takeoverWriter bool
961+ append bool
954962}
955963
956964// getObjectChecksums determines what checksum information to include in the final
@@ -965,20 +973,30 @@ func getObjectChecksums(params *getObjectChecksumsParams) *storagepb.ObjectCheck
965973 return nil
966974 }
967975
976+ // For append operations, send user's final append checksum on last write op if available.
977+ // Auto checksum is not supported for appendable writes.
978+ var crc32c * uint32
979+ if params .fullObjectChecksum != nil {
980+ crc32c = params .fullObjectChecksum ()
981+ }
982+
983+ if params .append && crc32c != nil {
984+ return & storagepb.ObjectChecksums {Crc32C : crc32c }
985+ }
986+
968987 // send user's checksum on last write op if available
969988 if params .sendCRC32C || (params .objectAttrs != nil && params .objectAttrs .MD5 != nil ) {
970989 return toProtoChecksums (params .sendCRC32C , params .objectAttrs )
971990 }
972- // TODO(b/461982277): Enable checksum validation for appendable takeover writer gRPC
973- if params .disableAutoChecksum || params .takeoverWriter {
974- return nil
975- }
976- if params .fullObjectChecksum == nil {
991+
992+ if params .append || params .disableAutoChecksum || params .fullObjectChecksum == nil {
977993 return nil
978994 }
979- return & storagepb.ObjectChecksums {
980- Crc32C : proto .Uint32 (params .fullObjectChecksum ()),
995+
996+ if crc32c != nil {
997+ return & storagepb.ObjectChecksums {Crc32C : crc32c }
981998 }
999+ return nil
9821000}
9831001
9841002type gRPCBidiWriteBufferSender interface {
@@ -1014,7 +1032,7 @@ type gRPCOneshotBidiWriteBufferSender struct {
10141032 sendCRC32C bool
10151033 disableAutoChecksum bool
10161034 objectAttrs * ObjectAttrs
1017- fullObjectChecksum func () uint32
1035+ fullObjectChecksum func () * uint32
10181036}
10191037
10201038func (w * gRPCWriter ) newGRPCOneshotBidiWriteBufferSender () * gRPCOneshotBidiWriteBufferSender {
@@ -1031,8 +1049,9 @@ func (w *gRPCWriter) newGRPCOneshotBidiWriteBufferSender() *gRPCOneshotBidiWrite
10311049 sendCRC32C : w .sendCRC32C ,
10321050 disableAutoChecksum : w .disableAutoChecksum ,
10331051 objectAttrs : w .attrs ,
1034- fullObjectChecksum : func () uint32 {
1035- return w .fullObjectChecksum
1052+ fullObjectChecksum : func () * uint32 {
1053+ checksum := w .fullObjectChecksum
1054+ return & checksum
10361055 },
10371056 }
10381057}
@@ -1151,7 +1170,7 @@ type gRPCResumableBidiWriteBufferSender struct {
11511170 sendCRC32C bool
11521171 disableAutoChecksum bool
11531172 objectAttrs * ObjectAttrs
1154- fullObjectChecksum func () uint32
1173+ fullObjectChecksum func () * uint32
11551174
11561175 streamErr error
11571176}
@@ -1168,8 +1187,9 @@ func (w *gRPCWriter) newGRPCResumableBidiWriteBufferSender() *gRPCResumableBidiW
11681187 sendCRC32C : w .sendCRC32C ,
11691188 disableAutoChecksum : w .disableAutoChecksum ,
11701189 objectAttrs : w .attrs ,
1171- fullObjectChecksum : func () uint32 {
1172- return w .fullObjectChecksum
1190+ fullObjectChecksum : func () * uint32 {
1191+ checksum := w .fullObjectChecksum
1192+ return & checksum
11731193 },
11741194 }
11751195}
@@ -1299,7 +1319,7 @@ type gRPCAppendBidiWriteBufferSender struct {
12991319 sendCRC32C bool
13001320 disableAutoChecksum bool
13011321 objectAttrs * ObjectAttrs
1302- fullObjectChecksum func () uint32
1322+ fullObjectChecksum func () * uint32
13031323
13041324 takeoverWriter bool
13051325
@@ -1323,8 +1343,12 @@ func (w *gRPCWriter) newGRPCAppendableObjectBufferSender() *gRPCAppendBidiWriteB
13231343 sendCRC32C : w .sendCRC32C ,
13241344 disableAutoChecksum : w .disableAutoChecksum ,
13251345 objectAttrs : w .attrs ,
1326- fullObjectChecksum : func () uint32 {
1327- return w .fullObjectChecksum
1346+ fullObjectChecksum : func () * uint32 {
1347+ if ! w .sendAppendFinalCRC32C {
1348+ return nil
1349+ }
1350+ checksum := w .appendFinalCRC32C
1351+ return & checksum
13281352 },
13291353 }
13301354}
@@ -1439,8 +1463,12 @@ func (w *gRPCWriter) newGRPCAppendTakeoverWriteBufferSender() *gRPCAppendTakeove
14391463 sendCRC32C : w .sendCRC32C ,
14401464 disableAutoChecksum : w .disableAutoChecksum ,
14411465 objectAttrs : w .attrs ,
1442- fullObjectChecksum : func () uint32 {
1443- return w .fullObjectChecksum
1466+ fullObjectChecksum : func () * uint32 {
1467+ if ! w .sendAppendFinalCRC32C {
1468+ return nil
1469+ }
1470+ checksum := w .appendFinalCRC32C
1471+ return & checksum
14441472 },
14451473 },
14461474 takeoverReported : false ,
@@ -1582,7 +1610,7 @@ func (s *gRPCAppendBidiWriteBufferSender) send(stream storagepb.Storage_BidiWrit
15821610 fullObjectChecksum : s .fullObjectChecksum ,
15831611 disableAutoChecksum : s .disableAutoChecksum ,
15841612 finishWrite : finalizeObject ,
1585- takeoverWriter : s . takeoverWriter ,
1613+ append : true ,
15861614 })
15871615 req := bidiWriteObjectRequest (r , bufChecksum , objectChecksums )
15881616 if sendFirstMessage {
0 commit comments