maintenance: disabled automatic compaction on repository opening

instead moved to run as part of maintenance ('kopia maintenance run')

added 'kopia maintenance run --force' flag which runs maintenance even
if not owned
This commit is contained in:
Jarek Kowalski
2020-05-30 22:49:24 -07:00
committed by Julio López
parent 6cb970f156
commit 960c33475e
8 changed files with 57 additions and 15 deletions

View File

@@ -165,7 +165,17 @@ func maybeRunMaintenance(ctx context.Context, rep repo.Repository) error {
return nil
}
return snapshotmaintenance.Run(ctx, rep, maintenance.ModeAuto)
err := snapshotmaintenance.Run(ctx, rep, maintenance.ModeAuto, false)
if err == nil {
return nil
}
if _, ok := err.(maintenance.NotOwnedError); ok {
// do not report the NotOwnedError to the user since this is automatic maintenance.
return nil
}
return err
}
// App returns an instance of command-line application object.

View File

@@ -11,6 +11,7 @@
var (
maintenanceRunCommand = maintenanceCommands.Command("run", "Run repository maintenance").Default()
maintenanceRunFull = maintenanceRunCommand.Flag("full", "Full maintenance").Bool()
maintenanceRunForce = maintenanceRunCommand.Flag("force", "Run maintenance even if not owned (unsafe)").Hidden().Bool()
)
func runMaintenanceCommand(ctx context.Context, rep *repo.DirectRepository) error {
@@ -19,7 +20,7 @@ func runMaintenanceCommand(ctx context.Context, rep *repo.DirectRepository) erro
mode = maintenance.ModeFull
}
return snapshotmaintenance.Run(ctx, rep, mode)
return snapshotmaintenance.Run(ctx, rep, mode, *maintenanceRunForce)
}
func init() {

View File

@@ -267,7 +267,7 @@ func (s *Server) periodicMaintenance(ctx context.Context, r repo.Repository) {
return
case <-time.After(maintenanceAttemptFrequency):
if err := snapshotmaintenance.Run(ctx, r, maintenance.ModeAuto); err != nil {
if err := snapshotmaintenance.Run(ctx, r, maintenance.ModeAuto, false); err != nil {
log(ctx).Warningf("unable to run maintenance: %v", err)
}
}

View File

@@ -722,8 +722,8 @@ func newManagerWithOptions(ctx context.Context, st blob.Storage, f *FormattingOp
return nil, errors.Wrap(err, "unable to set up caches")
}
if err := m.CompactIndexes(ctx, autoCompactionOptions); err != nil {
return nil, errors.Wrap(err, "error initializing content manager")
if _, _, err := m.loadPackIndexesUnlocked(ctx); err != nil {
return nil, errors.Wrap(err, "error loading indexes")
}
return m, nil

View File

@@ -12,10 +12,6 @@
const verySmallContentFraction = 20 // blobs less than 1/verySmallContentFraction of maxPackSize are considered 'very small'
var autoCompactionOptions = CompactOptions{
MaxSmallBlobs: 4 * parallelFetches, // nolint:gomnd
}
// CompactOptions provides options for compaction
type CompactOptions struct {
MaxSmallBlobs int

View File

@@ -0,0 +1,18 @@
package maintenance
import (
"context"
"github.com/kopia/kopia/repo/content"
)
const maxSmallBlobsForIndexCompaction = 8
// IndexCompaction rewrites index blobs to reduce their count but does not drop any contents.
func IndexCompaction(ctx context.Context, rep MaintainableRepository) error {
log(ctx).Infof("Compacting indexes...")
return rep.ContentManager().CompactIndexes(ctx, content.CompactOptions{
MaxSmallBlobs: maxSmallBlobsForIndexCompaction,
})
}

View File

@@ -136,18 +136,28 @@ type RunParameters struct {
Params *Params
}
// NotOwnedError is returned when maintenance cannot run because it is owned by another user.
type NotOwnedError struct {
Owner string
}
func (e NotOwnedError) Error() string {
return "maintenance must be run by designated user: " + e.Owner
}
// RunExclusive runs the provided callback if the maintenance is owned by local user and
// lock can be acquired. Lock is passed to the function, which ensures that every call to Run()
// is within the exclusive context.
func RunExclusive(ctx context.Context, rep MaintainableRepository, mode Mode, cb func(runParams RunParameters) error) error {
func RunExclusive(ctx context.Context, rep MaintainableRepository, mode Mode, force bool, cb func(runParams RunParameters) error) error {
p, err := GetParams(ctx, rep)
if err != nil {
return errors.Wrap(err, "unable to get maintenance params")
}
if myUsername := rep.Username() + "@" + rep.Hostname(); p.Owner != myUsername {
log(ctx).Debugf("maintenance owned by another user '%v'", p.Owner)
return nil
if !force {
if myUsername := rep.Username() + "@" + rep.Hostname(); p.Owner != myUsername {
return NotOwnedError{p.Owner}
}
}
if mode == ModeAuto {
@@ -231,6 +241,13 @@ func runQuickMaintenance(ctx context.Context, runParams RunParameters) error {
return errors.Wrap(err, "error deleting unreferenced metadata blobs")
}
// consolidate many smaller indexes into fewer larger ones.
if err := ReportRun(ctx, runParams.rep, "index-compaction", func() error {
return IndexCompaction(ctx, runParams.rep)
}); err != nil {
return errors.Wrap(err, "error performing index compaction")
}
return nil
}

View File

@@ -12,13 +12,13 @@
)
// Run runs the complete snapshot and repository maintenance.
func Run(ctx context.Context, rep repo.Repository, mode maintenance.Mode) error {
func Run(ctx context.Context, rep repo.Repository, mode maintenance.Mode, force bool) error {
dr, ok := rep.(*repo.DirectRepository)
if !ok {
return nil
}
return maintenance.RunExclusive(ctx, dr, mode,
return maintenance.RunExclusive(ctx, dr, mode, force,
func(runParams maintenance.RunParameters) error {
// run snapshot GC before full maintenance
if runParams.Mode == maintenance.ModeFull {