mirror of
https://github.com/pgsty/minio.git
synced 2026-10-30 04:20:36 +03:00
Preserve maintenance timeout behavior and prepare SILO 20261026
Signed-off-by: Feng Ruohang <rh@vonng.com>
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
// Copyright (c) 2026 Feng Ruohang
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
"testing/synctest"
|
||||
|
||||
"github.com/minio/minio/internal/grid"
|
||||
)
|
||||
|
||||
type cancelableRenameDisk struct {
|
||||
StorageAPI
|
||||
entered chan<- struct{}
|
||||
release <-chan struct{}
|
||||
}
|
||||
|
||||
func (d cancelableRenameDisk) RenameData(ctx context.Context, _, _ string, _ FileInfo, _, _ string, _ RenameOptions) (RenameDataResp, error) {
|
||||
d.entered <- struct{}{}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return RenameDataResp{}, ctx.Err()
|
||||
case <-d.release:
|
||||
return RenameDataResp{}, errDiskNotFound
|
||||
}
|
||||
}
|
||||
|
||||
func TestStorageTimeoutCoordinatorCancellation(t *testing.T) {
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
defer cancel()
|
||||
entered, release := make(chan struct{}, 4), make(chan struct{})
|
||||
defer close(release)
|
||||
disks := make([]StorageAPI, 4)
|
||||
metadata := make([]FileInfo, 4)
|
||||
for i := range disks {
|
||||
disks[i] = cancelableRenameDisk{entered: entered, release: release}
|
||||
metadata[i] = FileInfo{Deleted: true}
|
||||
}
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
_, _, _, err := renameData(ctx, disks, minioMetaTmpBucket, "staged", metadata, "bucket", "object", 3)
|
||||
done <- err
|
||||
}()
|
||||
for range disks {
|
||||
<-entered
|
||||
}
|
||||
cancel()
|
||||
synctest.Wait()
|
||||
select {
|
||||
case err := <-done:
|
||||
if err == nil {
|
||||
t.Fatal("canceled commit unexpectedly succeeded")
|
||||
}
|
||||
default:
|
||||
t.Fatal("coordinator did not propagate cancellation to disk calls")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type rollbackOptionsDisk struct {
|
||||
StorageAPI
|
||||
mu sync.Mutex
|
||||
opts DeleteOptions
|
||||
}
|
||||
|
||||
func (d *rollbackOptionsDisk) DeleteVersion(_ context.Context, _, _ string, _ FileInfo, _ bool, opts DeleteOptions) error {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
d.opts = opts
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestStorageRollbackRPCOptions(t *testing.T) {
|
||||
endpoint, err := NewEndpoint(t.TempDir())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
disk := &rollbackOptionsDisk{}
|
||||
globalLocalDrivesMu.Lock()
|
||||
oldDrives, oldSets := globalLocalDrivesMap, globalLocalSetDrives
|
||||
globalLocalDrivesMap = map[string]StorageAPI{endpoint.String(): disk}
|
||||
globalLocalSetDrives = nil
|
||||
globalLocalDrivesMu.Unlock()
|
||||
defer func() {
|
||||
globalLocalDrivesMu.Lock()
|
||||
globalLocalDrivesMap, globalLocalSetDrives = oldDrives, oldSets
|
||||
globalLocalDrivesMu.Unlock()
|
||||
}()
|
||||
tg, err := grid.SetupTestGrid(2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer tg.Cleanup()
|
||||
server := storageRESTServer{endpoint: endpoint}
|
||||
const route = "/rollback-options"
|
||||
if err := storageDeleteVersionRPC.Register(tg.Managers[1], server.DeleteVersionHandler, route); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
client := &storageRESTClient{gridConn: tg.Managers[0].Connection(tg.Hosts[1]).Subroute(route)}
|
||||
client.diskID.Store(new(string))
|
||||
want := DeleteOptions{UndoWrite: true, OldDataDir: mustGetUUID()}
|
||||
if err := client.DeleteVersion(t.Context(), "bucket", "object", FileInfo{}, false, want); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
disk.mu.Lock()
|
||||
defer disk.mu.Unlock()
|
||||
if disk.opts != want {
|
||||
t.Fatalf("remote handler lost rollback options: got %+v, want %+v", disk.opts, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoragePrereleaseMetadataHidden(t *testing.T) {
|
||||
disk, _, err := newXLStorageTestSetup(t)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer disk.Close()
|
||||
if err := disk.MakeVol(t.Context(), "bucket"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fi := newFileInfo("object", 2, 2)
|
||||
fi.DataDir, fi.ModTime, fi.Erasure.Index = mustGetUUID(), UTCNow(), 1
|
||||
fi.Metadata = map[string]string{rollbackIDKey: mustGetUUID(), "user-key": "value"}
|
||||
if err := disk.WriteMetadata(t.Context(), "", "bucket", "object", fi); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := disk.ReadVersion(t.Context(), "", "bucket", "object", "", ReadOptions{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
public := cleanMetadata(got.Metadata)
|
||||
if _, ok := public[rollbackIDKey]; ok || public["user-key"] != "value" {
|
||||
t.Fatalf("pre-release metadata exposed or user metadata lost: %+v", public)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user