github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libgit/util.go (about)

     1  // Copyright 2018 Keybase Inc. All rights reserved.
     2  // Use of this source code is governed by a BSD
     3  // license that can be found in the LICENSE file.
     4  
     5  package libgit
     6  
     7  import (
     8  	"context"
     9  	"os"
    10  	"time"
    11  
    12  	"github.com/keybase/client/go/kbfs/libfs"
    13  	"github.com/keybase/client/go/kbfs/libkbfs"
    14  	"github.com/keybase/client/go/logger"
    15  )
    16  
    17  const (
    18  	workTimeLimit = 1 * time.Hour
    19  )
    20  
    21  // commonTime computes the current time according to our estimate of
    22  // the mdserver's time.  It's a very crude way of normalizing the
    23  // local clock.
    24  func commonTime(
    25  	ctx context.Context, mdserver libkbfs.MDServer, clock libkbfs.Clock,
    26  	log logger.Logger) time.Time {
    27  	offset, haveOffset := mdserver.OffsetFromServerTime()
    28  	if !haveOffset {
    29  		log.CDebugf(ctx, "No offset, cannot use common time; "+
    30  			"falling back to local time")
    31  		return clock.Now()
    32  	}
    33  	return clock.Now().Add(-offset)
    34  }
    35  
    36  // canDoWork creates a file that marks the start of some long-term
    37  // work by this node.  It should be called while a lock is taken on
    38  // the server.  It returns true if the caller should start doing the
    39  // work.
    40  func canDoWork(
    41  	ctx context.Context, mdserver libkbfs.MDServer, clock libkbfs.Clock,
    42  	fs *libfs.FS, workingFileName string, workLimit time.Duration,
    43  	log logger.Logger) (bool, error) {
    44  	fi, err := fs.Stat(workingFileName)
    45  	currCommonTime := commonTime(ctx, mdserver, clock, log)
    46  	switch {
    47  	case os.IsNotExist(err):
    48  		log.CDebugf(ctx, "Creating new working file %s", workingFileName)
    49  		f, err := fs.Create(workingFileName)
    50  		if err != nil {
    51  			return false, err
    52  		}
    53  		err = f.Close()
    54  		if err != nil {
    55  			return false, err
    56  		}
    57  	case err != nil:
    58  		return false, err
    59  	default: // err == nil
    60  		modCommonTime := fi.ModTime()
    61  		if modCommonTime.Add(workTimeLimit).After(currCommonTime) {
    62  			log.CDebugf(ctx, "Other worker is still working; "+
    63  				"modCommonTime=%s, currCommonTime=%s, workTimeLimit=%s",
    64  				modCommonTime, currCommonTime, workTimeLimit)
    65  			// The other GC is still running within the time
    66  			// limit.
    67  			return false, nil
    68  		}
    69  		log.CDebugf(ctx, "Other GC expired; "+
    70  			"modCommonTime=%s, currCommonTime=%s, workTimeLimit=%s",
    71  			modCommonTime, currCommonTime, workTimeLimit)
    72  	}
    73  
    74  	log.CDebugf(ctx, "Setting work common time to %s", currCommonTime)
    75  	err = fs.Chtimes(workingFileName, time.Time{}, currCommonTime)
    76  	if err != nil {
    77  		return false, err
    78  	}
    79  	return true, nil
    80  }