implement a safer completeMultipart implementation (#20227)

- optimize writing part.N.meta by writing both part.N
  and its meta in sequence without network component.

- remove part.N.meta, part.N which were partially success
  ful, in quorum loss situations during renamePart()

- allow for strict read quorum check arbitrated via ETag
  for the given part number, this makes it double safer
  upon final commit.

- return an appropriate error when read quorum is missing,
  instead of returning InvalidPart{}, which is non-retryable
  error. This kind of situation can happen when many
  nodes are going offline in rotation, an example of such
  a restart() behavior is statefulset updates in k8s.

fixes #20091
This commit is contained in:
Harshavardhana
2024-08-12 01:38:15 -07:00
committed by GitHub
parent 909b169593
commit 2e0fd2cba9
19 changed files with 1487 additions and 275 deletions

View File

@@ -757,6 +757,55 @@ func (client *storageRESTClient) DeleteVersions(ctx context.Context, volume stri
return errs
}
// RenamePart - renames multipart part file
func (client *storageRESTClient) RenamePart(ctx context.Context, srcVolume, srcPath, dstVolume, dstPath string, meta []byte) (err error) {
ctx, cancel := context.WithTimeout(ctx, globalDriveConfig.GetMaxTimeout())
defer cancel()
_, err = storageRenamePartRPC.Call(ctx, client.gridConn, &RenamePartHandlerParams{
DiskID: *client.diskID.Load(),
SrcVolume: srcVolume,
SrcFilePath: srcPath,
DstVolume: dstVolume,
DstFilePath: dstPath,
Meta: meta,
})
return toStorageErr(err)
}
// ReadParts - reads various part.N.meta paths from a drive remotely and returns object part info for each of those part.N.meta if found
func (client *storageRESTClient) ReadParts(ctx context.Context, volume string, partMetaPaths ...string) ([]*ObjectPartInfo, error) {
values := make(url.Values)
values.Set(storageRESTVolume, volume)
rp := &ReadPartsReq{Paths: partMetaPaths}
buf, err := rp.MarshalMsg(nil)
if err != nil {
return nil, err
}
respBody, err := client.call(ctx, storageRESTMethodReadParts, values, bytes.NewReader(buf), -1)
defer xhttp.DrainBody(respBody)
if err != nil {
return nil, err
}
respReader, err := waitForHTTPResponse(respBody)
if err != nil {
return nil, toStorageErr(err)
}
rd := msgpNewReader(respReader)
defer readMsgpReaderPoolPut(rd)
readPartsResp := &ReadPartsResp{}
if err = readPartsResp.DecodeMsg(rd); err != nil {
return nil, toStorageErr(err)
}
return readPartsResp.Infos, nil
}
// RenameFile - renames a file.
func (client *storageRESTClient) RenameFile(ctx context.Context, srcVolume, srcPath, dstVolume, dstPath string) (err error) {
ctx, cancel := context.WithTimeout(ctx, globalDriveConfig.GetMaxTimeout())