|
|
|
@ -25,6 +25,7 @@ type VacuumTask struct { |
|
|
|
garbageThreshold float64 |
|
|
|
progress float64 |
|
|
|
grpcDialOption grpc.DialOption |
|
|
|
volumeSize uint64 |
|
|
|
} |
|
|
|
|
|
|
|
// NewVacuumTask creates a new unified vacuum task instance
|
|
|
|
@ -51,6 +52,7 @@ func (t *VacuumTask) Execute(ctx context.Context, params *worker_pb.TaskParams) |
|
|
|
} |
|
|
|
|
|
|
|
t.garbageThreshold = vacuumParams.GarbageThreshold |
|
|
|
t.volumeSize = params.VolumeSize |
|
|
|
|
|
|
|
t.GetLogger().WithFields(map[string]interface{}{ |
|
|
|
"volume_id": t.volumeID, |
|
|
|
@ -62,7 +64,7 @@ func (t *VacuumTask) Execute(ctx context.Context, params *worker_pb.TaskParams) |
|
|
|
// Step 1: Check volume status and garbage ratio
|
|
|
|
t.ReportProgress(10.0) |
|
|
|
t.GetLogger().Info("Checking volume status") |
|
|
|
eligible, currentGarbageRatio, err := t.checkVacuumEligibility() |
|
|
|
eligible, currentGarbageRatio, err := t.checkVacuumEligibility(ctx) |
|
|
|
if err != nil { |
|
|
|
return fmt.Errorf("failed to check vacuum eligibility: %v", err) |
|
|
|
} |
|
|
|
@ -83,14 +85,14 @@ func (t *VacuumTask) Execute(ctx context.Context, params *worker_pb.TaskParams) |
|
|
|
"threshold": t.garbageThreshold, |
|
|
|
}).Info("Performing vacuum operation") |
|
|
|
|
|
|
|
if err := t.performVacuum(); err != nil { |
|
|
|
if err := t.performVacuum(ctx); err != nil { |
|
|
|
return fmt.Errorf("failed to perform vacuum: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
// Step 3: Verify vacuum results
|
|
|
|
t.ReportProgress(90.0) |
|
|
|
t.GetLogger().Info("Verifying vacuum results") |
|
|
|
if err := t.verifyVacuumResults(); err != nil { |
|
|
|
if err := t.verifyVacuumResults(ctx); err != nil { |
|
|
|
glog.Warningf("Vacuum verification failed: %v", err) |
|
|
|
// Don't fail the task - vacuum operation itself succeeded
|
|
|
|
} |
|
|
|
@ -146,15 +148,28 @@ func (t *VacuumTask) GetProgress() float64 { |
|
|
|
return t.progress |
|
|
|
} |
|
|
|
|
|
|
|
// vacuumTimeout returns a dynamic timeout scaled by volume size, matching the
|
|
|
|
// topology vacuum approach. base is the per-GB multiplier (e.g. 1 minute for
|
|
|
|
// check, 3 minutes for compact).
|
|
|
|
func (t *VacuumTask) vacuumTimeout(base time.Duration) time.Duration { |
|
|
|
if t.volumeSize == 0 { |
|
|
|
glog.V(1).Infof("volume %d has no size metric, using minimum timeout", t.volumeID) |
|
|
|
} |
|
|
|
sizeGB := int64(t.volumeSize/1024/1024/1024) + 1 |
|
|
|
return base * time.Duration(sizeGB) |
|
|
|
} |
|
|
|
|
|
|
|
// Helper methods for real vacuum operations
|
|
|
|
|
|
|
|
// checkVacuumEligibility checks if the volume meets vacuum criteria
|
|
|
|
func (t *VacuumTask) checkVacuumEligibility() (bool, float64, error) { |
|
|
|
func (t *VacuumTask) checkVacuumEligibility(ctx context.Context) (bool, float64, error) { |
|
|
|
var garbageRatio float64 |
|
|
|
|
|
|
|
err := operation.WithVolumeServerClient(false, pb.ServerAddress(t.server), t.grpcDialOption, |
|
|
|
func(client volume_server_pb.VolumeServerClient) error { |
|
|
|
resp, err := client.VacuumVolumeCheck(context.Background(), &volume_server_pb.VacuumVolumeCheckRequest{ |
|
|
|
checkCtx, cancel := context.WithTimeout(ctx, t.vacuumTimeout(time.Minute)) |
|
|
|
defer cancel() |
|
|
|
resp, err := client.VacuumVolumeCheck(checkCtx, &volume_server_pb.VacuumVolumeCheckRequest{ |
|
|
|
VolumeId: t.volumeID, |
|
|
|
}) |
|
|
|
if err != nil { |
|
|
|
@ -178,12 +193,14 @@ func (t *VacuumTask) checkVacuumEligibility() (bool, float64, error) { |
|
|
|
} |
|
|
|
|
|
|
|
// performVacuum executes the actual vacuum operation
|
|
|
|
func (t *VacuumTask) performVacuum() error { |
|
|
|
func (t *VacuumTask) performVacuum(ctx context.Context) error { |
|
|
|
return operation.WithVolumeServerClient(false, pb.ServerAddress(t.server), t.grpcDialOption, |
|
|
|
func(client volume_server_pb.VolumeServerClient) error { |
|
|
|
// Step 1: Compact the volume
|
|
|
|
// Step 1: Compact the volume (3 min per GB, matching topology vacuum)
|
|
|
|
t.GetLogger().Info("Compacting volume") |
|
|
|
stream, err := client.VacuumVolumeCompact(context.Background(), &volume_server_pb.VacuumVolumeCompactRequest{ |
|
|
|
compactCtx, compactCancel := context.WithTimeout(ctx, t.vacuumTimeout(3*time.Minute)) |
|
|
|
defer compactCancel() |
|
|
|
stream, err := client.VacuumVolumeCompact(compactCtx, &volume_server_pb.VacuumVolumeCompactRequest{ |
|
|
|
VolumeId: t.volumeID, |
|
|
|
}) |
|
|
|
if err != nil { |
|
|
|
@ -202,18 +219,22 @@ func (t *VacuumTask) performVacuum() error { |
|
|
|
glog.V(2).Infof("Volume %d compact progress: %d bytes processed", t.volumeID, resp.ProcessedBytes) |
|
|
|
} |
|
|
|
|
|
|
|
// Step 2: Commit the vacuum
|
|
|
|
// Step 2: Commit the vacuum (1 min per GB)
|
|
|
|
t.GetLogger().Info("Committing vacuum operation") |
|
|
|
_, err = client.VacuumVolumeCommit(context.Background(), &volume_server_pb.VacuumVolumeCommitRequest{ |
|
|
|
commitCtx, commitCancel := context.WithTimeout(ctx, t.vacuumTimeout(time.Minute)) |
|
|
|
defer commitCancel() |
|
|
|
_, err = client.VacuumVolumeCommit(commitCtx, &volume_server_pb.VacuumVolumeCommitRequest{ |
|
|
|
VolumeId: t.volumeID, |
|
|
|
}) |
|
|
|
if err != nil { |
|
|
|
return fmt.Errorf("vacuum commit failed: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
// Step 3: Cleanup old files
|
|
|
|
// Step 3: Cleanup old files (1 min per GB)
|
|
|
|
t.GetLogger().Info("Cleaning up vacuum files") |
|
|
|
_, err = client.VacuumVolumeCleanup(context.Background(), &volume_server_pb.VacuumVolumeCleanupRequest{ |
|
|
|
cleanupCtx, cleanupCancel := context.WithTimeout(ctx, t.vacuumTimeout(time.Minute)) |
|
|
|
defer cleanupCancel() |
|
|
|
_, err = client.VacuumVolumeCleanup(cleanupCtx, &volume_server_pb.VacuumVolumeCleanupRequest{ |
|
|
|
VolumeId: t.volumeID, |
|
|
|
}) |
|
|
|
if err != nil { |
|
|
|
@ -226,10 +247,12 @@ func (t *VacuumTask) performVacuum() error { |
|
|
|
} |
|
|
|
|
|
|
|
// verifyVacuumResults checks the volume status after vacuum
|
|
|
|
func (t *VacuumTask) verifyVacuumResults() error { |
|
|
|
func (t *VacuumTask) verifyVacuumResults(ctx context.Context) error { |
|
|
|
return operation.WithVolumeServerClient(false, pb.ServerAddress(t.server), t.grpcDialOption, |
|
|
|
func(client volume_server_pb.VolumeServerClient) error { |
|
|
|
resp, err := client.VacuumVolumeCheck(context.Background(), &volume_server_pb.VacuumVolumeCheckRequest{ |
|
|
|
verifyCtx, cancel := context.WithTimeout(ctx, t.vacuumTimeout(time.Minute)) |
|
|
|
defer cancel() |
|
|
|
resp, err := client.VacuumVolumeCheck(verifyCtx, &volume_server_pb.VacuumVolumeCheckRequest{ |
|
|
|
VolumeId: t.volumeID, |
|
|
|
}) |
|
|
|
if err != nil { |
|
|
|
|