github.com/swiftstack/ProxyFS@v0.0.0-20210203235616-4017c267d62f/pfsagentd/globals.go (about)

     1  // Copyright (c) 2015-2021, NVIDIA CORPORATION.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package main
     5  
     6  import (
     7  	"container/list"
     8  	"fmt"
     9  	"io"
    10  	"log"
    11  	"math"
    12  	"net/http"
    13  	"os"
    14  	"os/exec"
    15  	"sync"
    16  	"time"
    17  
    18  	"bazil.org/fuse"
    19  
    20  	"github.com/swiftstack/fission"
    21  	"github.com/swiftstack/sortedmap"
    22  
    23  	"github.com/swiftstack/ProxyFS/bucketstats"
    24  	"github.com/swiftstack/ProxyFS/conf"
    25  	"github.com/swiftstack/ProxyFS/inode"
    26  	"github.com/swiftstack/ProxyFS/jrpcfs"
    27  	"github.com/swiftstack/ProxyFS/retryrpc"
    28  	"github.com/swiftstack/ProxyFS/utils"
    29  )
    30  
    31  type configStruct struct {
    32  	FUSEVolumeName               string
    33  	FUSEMountPointPath           string // Unless starting with '/', relative to $CWD
    34  	FUSEUnMountRetryDelay        time.Duration
    35  	FUSEUnMountRetryCap          uint64
    36  	PlugInPath                   string
    37  	PlugInEnvName                string
    38  	PlugInEnvValue               string // If "", assume it's already set as desired
    39  	SwiftTimeout                 time.Duration
    40  	SwiftRetryLimit              uint64
    41  	SwiftRetryDelay              time.Duration
    42  	SwiftRetryDelayVariance      uint8
    43  	SwiftRetryExpBackoff         float64
    44  	SwiftConnectionPoolSize      uint64
    45  	FetchExtentsFromFileOffset   uint64
    46  	FetchExtentsBeforeFileOffset uint64
    47  	ReadCacheLineSize            uint64 // Aligned chunk of a LogSegment
    48  	ReadCacheLineCount           uint64
    49  	LeaseRetryLimit              uint64
    50  	LeaseRetryDelay              time.Duration
    51  	LeaseRetryDelayVariance      uint8
    52  	LeaseRetryExpBackoff         float64
    53  	SharedLeaseLimit             uint64
    54  	ExclusiveLeaseLimit          uint64
    55  	ExtentMapEntryLimit          uint64
    56  	DirtyLogSegmentLimit         uint64
    57  	DirtyFileLimit               uint64 // TODO - obsolete this
    58  	MaxFlushSize                 uint64
    59  	MaxFlushTime                 time.Duration
    60  	LogFilePath                  string // Unless starting with '/', relative to $CWD; == "" means disabled
    61  	LogToConsole                 bool
    62  	TraceEnabled                 bool
    63  	HTTPServerIPAddr             string
    64  	HTTPServerTCPPort            uint16
    65  	ReadDirPlusEnabled           bool
    66  	XAttrEnabled                 bool
    67  	EntryDuration                time.Duration
    68  	AttrDuration                 time.Duration
    69  	AttrBlockSize                uint64
    70  	ReaddirMaxEntries            uint64
    71  	FUSEMaxBackground            uint16
    72  	FUSECongestionThreshhold     uint16
    73  	FUSEMaxWrite                 uint32
    74  	RetryRPCDeadlineIO           time.Duration
    75  	RetryRPCKeepAlivePeriod      time.Duration
    76  }
    77  
    78  type retryDelayElementStruct struct {
    79  	nominal  time.Duration
    80  	variance time.Duration
    81  }
    82  
    83  type fileInodeLeaseStateType uint32
    84  
    85  const (
    86  	fileInodeLeaseStateNone fileInodeLeaseStateType = iota
    87  	fileInodeLeaseStateSharedRequested
    88  	fileInodeLeaseStateSharedGranted
    89  	fileInodeLeaseStateSharedPromoting
    90  	fileInodeLeaseStateSharedReleasing
    91  	fileInodeLeaseStateExclusiveRequested
    92  	fileInodeLeaseStateExclusiveGranted
    93  	fileInodeLeaseStateExclusiveDemoting
    94  	fileInodeLeaseStateExclusiveReleasing
    95  )
    96  
    97  type fileInodeLeaseRequestType uint32
    98  
    99  const (
   100  	fileInodeLeaseRequestShutdown fileInodeLeaseRequestType = iota
   101  	fileInodeLeaseRequestShared
   102  	fileInodeLeaseRequestExclusive
   103  	fileInodeLeaseRequestDemote
   104  	fileInodeLeaseRequestRelease
   105  )
   106  
   107  // singleObjectExtentStruct is used for chunkedPutContextStruct.extentMap.
   108  //
   109  type singleObjectExtentStruct struct {
   110  	fileOffset   uint64 // Key in chunkedPutContextStruct.extentMap
   111  	objectOffset uint64
   112  	length       uint64
   113  }
   114  
   115  // singleObjectExtentWithLinkStruct is used to represent a ReadPlanStep. A chunkedPutContext == nil
   116  // indicates a zero-filled extent rather that a read from a LogSegment not yet persisted by Swift.
   117  //
   118  type singleObjectExtentWithLinkStruct struct {
   119  	fileOffset        uint64
   120  	objectOffset      uint64
   121  	length            uint64
   122  	chunkedPutContext *chunkedPutContextStruct // If == nil, implies a zero-filled extent/ReadPlanStep
   123  }
   124  
   125  // multiObjectExtentStruct is used for both the fileInodeStruct.extentMap as well
   126  // as for representing a ReadPlanStep. In this latter case, an objectName == ""
   127  // indicates a zero-filled extent rather than a read from a LogSegment already
   128  // persisted by Swift.
   129  //
   130  type multiObjectExtentStruct struct {
   131  	fileOffset    uint64 // Key in fileInodeStruct.extentMap
   132  	containerName string
   133  	objectName    string // If == "", implies a zero-filled extent/ReadPlanStep
   134  	objectOffset  uint64
   135  	length        uint64
   136  }
   137  
   138  const (
   139  	chunkedPutContextStateOpen    uint8 = iota // Initial state indicating Chunked PUT is available to send a chunk
   140  	chunkedPutContextStateClosing              // After a zero-length chunk is sent to close the Chunked PUT... awaiting http.StatusCreated
   141  	chunkedPutContextStateClosed               // Chunked PUT received an http.StatusCreated...
   142  	//                                              but we cannot yet merge it's ExtentMap updates because
   143  	//                                              an as-yet un-closed Chunked PUT needs to do so first
   144  	chunkedPutContextExitReadPollingRate = time.Millisecond
   145  )
   146  
   147  type chunkedPutContextStruct struct {
   148  	sync.WaitGroup                           // Used to await completion of performChunkedPut goroutine
   149  	containerName         string             //
   150  	objectName            string             //
   151  	extentMap             sortedmap.LLRBTree // Key == singleObjectExtentStruct.fileOffset; Value == *singleObjectExtentStruct
   152  	buf                   []byte             //
   153  	chunkedPutListElement *list.Element      // FIFO Element of fileInodeStruct.chunkedPutList
   154  	fileInode             *fileInodeStruct   //
   155  	state                 uint8              // One of chunkedPutContextState{Open|Closing|Closed}
   156  	pos                   int                // ObjectOffset just after last sent chunk
   157  	sendChan              chan struct{}      // Single element buffered chan to wake up *chunkedPutContextStruct.sendDaemon()
   158  	//                                            will be closed to indicate a flush is requested
   159  	wakeChan chan struct{} //                   Single element buffered chan to wake up *chunkedPutContextStruct.Read()
   160  	//                                            will be closed to indicate a flush is requested
   161  	inRead         bool //                      Set when in Read() as a hint to Close() to help Read() cleanly exit
   162  	flushRequested bool //                      Set to remember that a flush has been requested of *chunkedPutContextStruct.Read()
   163  }
   164  
   165  type fileInodeStruct struct {
   166  	inode.InodeNumber
   167  	cachedStat  *jrpcfs.StatStruct //                 Maintained valid/coherent with ProxyFS (possibly dirty until flushed)
   168  	lockWaiters *list.List         //                 List of chan struct{} lock waiters:
   169  	//                                                  If == nil, no lock requests
   170  	//                                                  If .Len() == 0, lock grant in progress or granted but no blocked lock requests
   171  	//                                                  If .Len() != 0, lock grant in progress or granted and other lock requests are waiting
   172  	leaseState            fileInodeLeaseStateType  // One of fileInodeLeaseState*
   173  	pendingLeaseInterrupt *jrpcfs.RPCInterruptType // If non-nil, either jrpcfs.RPCInterruptTypeDemote or jrpcfs.RPCInterruptTypeRelease
   174  	leaseListElement      *list.Element            // Element on one of {unleased|shared|exclusive}FileInodeCacheLRU
   175  	//                                                  On globals.unleasedFileInodeCacheLRU       if leaseState one of:
   176  	//                                                    fileInodeLeaseStateNone
   177  	//                                                    fileInodeLeaseStateSharedReleasing
   178  	//                                                    fileInodeLeaseStateExclusiveReleasing
   179  	//                                                  On globals.sharedLeaseFileInodeCacheLRU    if leaseState one of:
   180  	//                                                    fileInodeLeaseStateSharedRequested
   181  	//                                                    fileInodeLeaseStateSharedGranted
   182  	//                                                    fileInodeLeaseStateExclusiveDemoting
   183  	//                                                  On globals.exclusiveLeaseFileInodeCacheLRU if leaseState one of:
   184  	//                                                    fileInodeLeaseStateSharedPromoting
   185  	//                                                    fileInodeLeaseStateExclusiveRequested
   186  	//                                                    fileInodeLeaseStateExclusiveGranted
   187  	extentMap                 sortedmap.LLRBTree //   Key == multiObjectExtentStruct.fileOffset; Value == *multiObjectExtentStruct
   188  	chunkedPutList            *list.List         //   FIFO List of chunkedPutContextStruct's
   189  	flushInProgress           bool               //   Serializes (& singularizes) explicit Flush requests
   190  	chunkedPutFlushWaiterList *list.List         //   List of *sync.WaitGroup's for those awaiting an explicit Flush
   191  	//                                                  Note: These waiters cannot be holding fileInodeStruct.Lock
   192  	dirtyListElement *list.Element //                 Element on globals.fileInodeDirtyList (or nil)
   193  }
   194  
   195  type fhSetType map[uint64]struct{}
   196  
   197  type logSegmentCacheElementStateType uint8
   198  
   199  const (
   200  	logSegmentCacheElementStateGetIssued logSegmentCacheElementStateType = iota
   201  	logSegmentCacheElementStateGetSuccessful
   202  	logSegmentCacheElementStateGetFailed // In which case it must not be in LLRBTree nor LRU
   203  )
   204  
   205  type logSegmentCacheElementKeyStruct struct {
   206  	logSegmentNumber uint64 // Converted from logSegmentCacheElementStruct.objectName
   207  	cacheLineTag     uint64 // == logSegmentCacheElementStruct.offset / globals.config.ReadCacheLineSize
   208  }
   209  
   210  type logSegmentCacheElementStruct struct {
   211  	sync.WaitGroup                                  // Used by those awaiting GET result
   212  	state           logSegmentCacheElementStateType //  if logSegmentCacheElementStateGetIssued
   213  	containerName   string
   214  	objectName      string
   215  	startingOffset  uint64
   216  	cacheLRUElement *list.Element // Element on globals.logSegmentCacheLRU
   217  	buf             []byte
   218  }
   219  
   220  type authPlugInControlStruct struct {
   221  	cmd        *exec.Cmd
   222  	stdinPipe  io.WriteCloser
   223  	stdoutPipe io.ReadCloser
   224  	stderrPipe io.ReadCloser
   225  	stdoutChan chan []byte
   226  	stderrChan chan []byte
   227  	wg         sync.WaitGroup
   228  }
   229  
   230  // metricsStruct contains Prometheus-styled field names to be output by serveGetOfMetrics().
   231  //
   232  // In order to utilize Go Reflection, these field names must be capitalized (i.e. Global).
   233  
   234  type metricsStruct struct {
   235  	FUSE_DoLookup_calls      uint64
   236  	FUSE_DoForget_calls      uint64
   237  	FUSE_DoGetAttr_calls     uint64
   238  	FUSE_DoSetAttr_calls     uint64
   239  	FUSE_DoReadLink_calls    uint64
   240  	FUSE_DoSymLink_calls     uint64
   241  	FUSE_DoMkNod_calls       uint64
   242  	FUSE_DoMkDir_calls       uint64
   243  	FUSE_DoUnlink_calls      uint64
   244  	FUSE_DoRmDir_calls       uint64
   245  	FUSE_DoRename_calls      uint64
   246  	FUSE_DoLink_calls        uint64
   247  	FUSE_DoOpen_calls        uint64
   248  	FUSE_DoRead_calls        uint64
   249  	FUSE_DoWrite_calls       uint64
   250  	FUSE_DoStatFS_calls      uint64
   251  	FUSE_DoRelease_calls     uint64
   252  	FUSE_DoFSync_calls       uint64
   253  	FUSE_DoSetXAttr_calls    uint64
   254  	FUSE_DoGetXAttr_calls    uint64
   255  	FUSE_DoListXAttr_calls   uint64
   256  	FUSE_DoRemoveXAttr_calls uint64
   257  	FUSE_DoFlush_calls       uint64
   258  	FUSE_DoInit_calls        uint64
   259  	FUSE_DoOpenDir_calls     uint64
   260  	FUSE_DoReadDir_calls     uint64
   261  	FUSE_DoReleaseDir_calls  uint64
   262  	FUSE_DoFSyncDir_calls    uint64
   263  	FUSE_DoGetLK_calls       uint64
   264  	FUSE_DoSetLK_calls       uint64
   265  	FUSE_DoSetLKW_calls      uint64
   266  	FUSE_DoAccess_calls      uint64
   267  	FUSE_DoCreate_calls      uint64
   268  	FUSE_DoInterrupt_calls   uint64
   269  	FUSE_DoBMap_calls        uint64
   270  	FUSE_DoDestroy_calls     uint64
   271  	FUSE_DoPoll_calls        uint64
   272  	FUSE_DoBatchForget_calls uint64
   273  	FUSE_DoFAllocate_calls   uint64
   274  	FUSE_DoReadDirPlus_calls uint64
   275  	FUSE_DoRename2_calls     uint64
   276  	FUSE_DoLSeek_calls       uint64
   277  
   278  	FUSE_DoRead_bytes  uint64
   279  	FUSE_DoWrite_bytes uint64
   280  
   281  	FUSE_DoReadDir_entries     uint64
   282  	FUSE_DoReadDirPlus_entries uint64
   283  
   284  	FUSE_DoSetXAttr_bytes  uint64
   285  	FUSE_DoGetXAttr_bytes  uint64
   286  	FUSE_DoListXAttr_names uint64
   287  
   288  	FUSE_DoBatchForget_nodes uint64
   289  
   290  	ReadCacheHits   uint64
   291  	ReadCacheMisses uint64
   292  
   293  	LogSegmentPUTs        uint64
   294  	LogSegmentPUTReadHits uint64
   295  
   296  	LeaseRequests_Shared    uint64
   297  	LeaseRequests_Promote   uint64
   298  	LeaseRequests_Exclusive uint64
   299  	LeaseRequests_Demote    uint64
   300  	LeaseRequests_Release   uint64
   301  
   302  	LeaseInterrupts_Unmount uint64
   303  	LeaseInterrupts_Demote  uint64
   304  	LeaseInterrupts_Release uint64
   305  
   306  	HTTPRequests                         uint64
   307  	HTTPRequestSubmissionFailures        uint64
   308  	HTTPRequestResponseBodyCorruptions   uint64
   309  	HTTPRequestRetryLimitExceededCount   uint64
   310  	HTTPRequestsRequiringReauthorization uint64
   311  	HTTPRequestRetries                   uint64
   312  	HTTPRequestsInFlight                 uint64
   313  }
   314  
   315  type statsStruct struct {
   316  	FUSEDoReadBytes  bucketstats.BucketLog2Round
   317  	FUSEDoWriteBytes bucketstats.BucketLog2Round
   318  
   319  	LogSegmentGetUsec bucketstats.BucketLog2Round
   320  
   321  	LogSegmentPutBytes bucketstats.BucketLog2Round
   322  
   323  	LeaseRequests_Shared_Usec    bucketstats.BucketLog2Round
   324  	LeaseRequests_Promote_Usec   bucketstats.BucketLog2Round
   325  	LeaseRequests_Exclusive_Usec bucketstats.BucketLog2Round
   326  	LeaseRequests_Demote_Usec    bucketstats.BucketLog2Round
   327  	LeaseRequests_Release_Usec   bucketstats.BucketLog2Round
   328  }
   329  
   330  type globalsStruct struct {
   331  	sync.Mutex
   332  	config                          configStruct
   333  	logFile                         *os.File // == nil if configStruct.LogFilePath == ""
   334  	retryRPCPublicIPAddr            string
   335  	retryRPCPort                    uint16
   336  	retryRPCClient                  *retryrpc.Client
   337  	rootCAx509CertificatePEM        []byte
   338  	entryValidSec                   uint64
   339  	entryValidNSec                  uint32
   340  	attrValidSec                    uint64
   341  	attrValidNSec                   uint32
   342  	httpServer                      *http.Server
   343  	httpServerWG                    sync.WaitGroup
   344  	httpClient                      *http.Client
   345  	retryDelay                      []retryDelayElementStruct
   346  	authPlugInControl               *authPlugInControlStruct
   347  	swiftAuthWaitGroup              *sync.WaitGroup // Protected by sync.Mutex of globalsStruct
   348  	swiftAuthToken                  string          // Protected by swiftAuthWaitGroup
   349  	swiftStorageURL                 string          // Protected by swiftAuthWaitGroup
   350  	mountID                         jrpcfs.MountIDAsString
   351  	rootDirInodeNumber              uint64
   352  	fissionErrChan                  chan error
   353  	fissionVolume                   fission.Volume
   354  	fuseConn                        *fuse.Conn
   355  	jrpcLastID                      uint64
   356  	fileInodeMap                    map[inode.InodeNumber]*fileInodeStruct
   357  	fileInodeDirtyList              *list.List           // LRU of fileInode's with non-empty chunkedPutList
   358  	fileInodeDirtyLogSegmentChan    chan struct{}        // Limits # of in-flight LogSegment Chunked PUTs
   359  	unleasedFileInodeCacheLRU       *list.List           // Front() is oldest fileInodeStruct.leaseListElement
   360  	sharedLeaseFileInodeCacheLRU    *list.List           // Front() is oldest fileInodeStruct.leaseListElement
   361  	exclusiveLeaseFileInodeCacheLRU *list.List           // Front() is oldest fileInodeStruct.leaseListElement
   362  	fhToInodeNumberMap              map[uint64]uint64    // Key == FH; Value == InodeNumber
   363  	inodeNumberToFHMap              map[uint64]fhSetType // Key == InodeNumber; Value == set of FH's
   364  	lastFH                          uint64               // Valid FH's start at 1
   365  	logSegmentCacheMap              map[logSegmentCacheElementKeyStruct]*logSegmentCacheElementStruct
   366  	logSegmentCacheLRU              *list.List // Front() is oldest logSegmentCacheElementStruct.cacheLRUElement
   367  	metrics                         *metricsStruct
   368  	stats                           *statsStruct
   369  }
   370  
   371  var globals globalsStruct
   372  
   373  func initializeGlobals(confMap conf.ConfMap) {
   374  	var (
   375  		configJSONified                   string
   376  		customTransport                   *http.Transport
   377  		defaultTransport                  *http.Transport
   378  		err                               error
   379  		fileInodeDirtyLogSegmentChanIndex uint64
   380  		nextRetryDelay                    time.Duration
   381  		ok                                bool
   382  		plugInEnvValueSlice               []string
   383  		retryIndex                        uint64
   384  	)
   385  
   386  	// Default logging related globals
   387  
   388  	globals.config.LogFilePath = ""
   389  	globals.config.LogToConsole = true
   390  	globals.logFile = nil
   391  
   392  	// Process resultant confMap
   393  
   394  	globals.config.FUSEVolumeName, err = confMap.FetchOptionValueString("Agent", "FUSEVolumeName")
   395  	if nil != err {
   396  		logFatal(err)
   397  	}
   398  
   399  	globals.config.FUSEMountPointPath, err = confMap.FetchOptionValueString("Agent", "FUSEMountPointPath")
   400  	if nil != err {
   401  		logFatal(err)
   402  	}
   403  
   404  	globals.config.FUSEUnMountRetryDelay, err = confMap.FetchOptionValueDuration("Agent", "FUSEUnMountRetryDelay")
   405  	if nil != err {
   406  		logFatal(err)
   407  	}
   408  
   409  	globals.config.FUSEUnMountRetryCap, err = confMap.FetchOptionValueUint64("Agent", "FUSEUnMountRetryCap")
   410  	if nil != err {
   411  		logFatal(err)
   412  	}
   413  
   414  	globals.config.PlugInPath, err = confMap.FetchOptionValueString("Agent", "PlugInPath")
   415  	if nil != err {
   416  		logFatal(err)
   417  	}
   418  
   419  	globals.config.PlugInEnvName, err = confMap.FetchOptionValueString("Agent", "PlugInEnvName")
   420  	if nil != err {
   421  		logFatal(err)
   422  	}
   423  
   424  	err = confMap.VerifyOptionIsMissing("Agent", "PlugInEnvValue")
   425  	if nil == err {
   426  		globals.config.PlugInEnvValue = ""
   427  	} else {
   428  		plugInEnvValueSlice, err = confMap.FetchOptionValueStringSlice("Agent", "PlugInEnvValue")
   429  		if nil != err {
   430  			logFatal(err)
   431  		} else {
   432  			switch len(plugInEnvValueSlice) {
   433  			case 0:
   434  				globals.config.PlugInEnvValue = ""
   435  			case 1:
   436  				globals.config.PlugInEnvValue = plugInEnvValueSlice[0]
   437  			default:
   438  				log.Fatalf("[Agent]PlugInEnvValue must be missing, empty, or single-valued: %#v", plugInEnvValueSlice)
   439  			}
   440  		}
   441  	}
   442  
   443  	globals.config.SwiftTimeout, err = confMap.FetchOptionValueDuration("Agent", "SwiftTimeout")
   444  	if nil != err {
   445  		logFatal(err)
   446  	}
   447  
   448  	globals.config.SwiftRetryLimit, err = confMap.FetchOptionValueUint64("Agent", "SwiftRetryLimit")
   449  	if nil != err {
   450  		logFatal(err)
   451  	}
   452  
   453  	globals.config.SwiftRetryDelay, err = confMap.FetchOptionValueDuration("Agent", "SwiftRetryDelay")
   454  	if nil != err {
   455  		logFatal(err)
   456  	}
   457  
   458  	globals.config.SwiftRetryDelayVariance, err = confMap.FetchOptionValueUint8("Agent", "SwiftRetryDelayVariance")
   459  	if nil != err {
   460  		logFatal(err)
   461  	}
   462  	if 0 == globals.config.SwiftRetryDelayVariance {
   463  		err = fmt.Errorf("[Agent]SwiftRetryDelayVariance must be > 0")
   464  		logFatal(err)
   465  	}
   466  	if 100 < globals.config.SwiftRetryDelayVariance {
   467  		err = fmt.Errorf("[Agent]SwiftRetryDelayVariance (%v) must be <= 100", globals.config.SwiftRetryDelayVariance)
   468  		logFatal(err)
   469  	}
   470  
   471  	globals.config.SwiftRetryExpBackoff, err = confMap.FetchOptionValueFloat64("Agent", "SwiftRetryExpBackoff")
   472  	if nil != err {
   473  		logFatal(err)
   474  	}
   475  
   476  	globals.config.SwiftConnectionPoolSize, err = confMap.FetchOptionValueUint64("Agent", "SwiftConnectionPoolSize")
   477  	if nil != err {
   478  		logFatal(err)
   479  	}
   480  
   481  	globals.config.FetchExtentsFromFileOffset, err = confMap.FetchOptionValueUint64("Agent", "FetchExtentsFromFileOffset")
   482  	if nil != err {
   483  		logFatal(err)
   484  	}
   485  
   486  	globals.config.FetchExtentsBeforeFileOffset, err = confMap.FetchOptionValueUint64("Agent", "FetchExtentsBeforeFileOffset")
   487  	if nil != err {
   488  		logFatal(err)
   489  	}
   490  
   491  	globals.config.ReadCacheLineSize, err = confMap.FetchOptionValueUint64("Agent", "ReadCacheLineSize")
   492  	if nil != err {
   493  		logFatal(err)
   494  	}
   495  
   496  	globals.config.ReadCacheLineCount, err = confMap.FetchOptionValueUint64("Agent", "ReadCacheLineCount")
   497  	if nil != err {
   498  		logFatal(err)
   499  	}
   500  
   501  	globals.config.LeaseRetryLimit, err = confMap.FetchOptionValueUint64("Agent", "LeaseRetryLimit")
   502  	if nil != err {
   503  		logFatal(err)
   504  	}
   505  
   506  	globals.config.LeaseRetryDelay, err = confMap.FetchOptionValueDuration("Agent", "LeaseRetryDelay")
   507  	if nil != err {
   508  		logFatal(err)
   509  	}
   510  
   511  	globals.config.LeaseRetryDelayVariance, err = confMap.FetchOptionValueUint8("Agent", "LeaseRetryDelayVariance")
   512  	if nil != err {
   513  		logFatal(err)
   514  	}
   515  	if 0 == globals.config.LeaseRetryDelayVariance {
   516  		err = fmt.Errorf("[Agent]LeaseRetryDelayVariance must be > 0")
   517  		logFatal(err)
   518  	}
   519  	if 100 < globals.config.LeaseRetryDelayVariance {
   520  		err = fmt.Errorf("[Agent]LeaseRetryDelayVariance (%v) must be <= 100", globals.config.LeaseRetryDelayVariance)
   521  		logFatal(err)
   522  	}
   523  
   524  	globals.config.LeaseRetryExpBackoff, err = confMap.FetchOptionValueFloat64("Agent", "LeaseRetryExpBackoff")
   525  	if nil != err {
   526  		logFatal(err)
   527  	}
   528  
   529  	globals.config.SharedLeaseLimit, err = confMap.FetchOptionValueUint64("Agent", "SharedLeaseLimit")
   530  	if nil != err {
   531  		logFatal(err)
   532  	}
   533  
   534  	globals.config.ExclusiveLeaseLimit, err = confMap.FetchOptionValueUint64("Agent", "ExclusiveLeaseLimit")
   535  	if nil != err {
   536  		logFatal(err)
   537  	}
   538  
   539  	globals.config.ExtentMapEntryLimit, err = confMap.FetchOptionValueUint64("Agent", "ExtentMapEntryLimit")
   540  	if nil != err {
   541  		logFatal(err)
   542  	}
   543  
   544  	globals.config.DirtyLogSegmentLimit, err = confMap.FetchOptionValueUint64("Agent", "DirtyLogSegmentLimit")
   545  	if nil != err {
   546  		logFatal(err)
   547  	}
   548  
   549  	globals.config.DirtyFileLimit, err = confMap.FetchOptionValueUint64("Agent", "DirtyFileLimit")
   550  	if nil != err {
   551  		logFatal(err) // TODO - obsolete this
   552  	}
   553  
   554  	globals.config.MaxFlushSize, err = confMap.FetchOptionValueUint64("Agent", "MaxFlushSize")
   555  	if nil != err {
   556  		logFatal(err)
   557  	}
   558  
   559  	globals.config.MaxFlushTime, err = confMap.FetchOptionValueDuration("Agent", "MaxFlushTime")
   560  	if nil != err {
   561  		logFatal(err)
   562  	}
   563  
   564  	err = confMap.VerifyOptionValueIsEmpty("Agent", "LogFilePath")
   565  	if nil == err {
   566  		globals.config.LogFilePath = ""
   567  	} else {
   568  		globals.config.LogFilePath, err = confMap.FetchOptionValueString("Agent", "LogFilePath")
   569  		if nil != err {
   570  			logFatal(err)
   571  		}
   572  	}
   573  
   574  	globals.config.LogToConsole, err = confMap.FetchOptionValueBool("Agent", "LogToConsole")
   575  	if nil != err {
   576  		logFatal(err)
   577  	}
   578  
   579  	globals.config.TraceEnabled, err = confMap.FetchOptionValueBool("Agent", "TraceEnabled")
   580  	if nil != err {
   581  		logFatal(err)
   582  	}
   583  
   584  	globals.config.HTTPServerIPAddr, err = confMap.FetchOptionValueString("Agent", "HTTPServerIPAddr")
   585  	if nil != err {
   586  		logFatal(err)
   587  	}
   588  	globals.config.HTTPServerTCPPort, err = confMap.FetchOptionValueUint16("Agent", "HTTPServerTCPPort")
   589  	if nil != err {
   590  		logFatal(err)
   591  	}
   592  
   593  	globals.config.AttrDuration, err = confMap.FetchOptionValueDuration("Agent", "AttrDuration")
   594  	if nil != err {
   595  		logFatal(err)
   596  	}
   597  
   598  	globals.config.ReadDirPlusEnabled, err = confMap.FetchOptionValueBool("Agent", "ReadDirPlusEnabled")
   599  	if nil != err {
   600  		logFatal(err)
   601  	}
   602  
   603  	globals.config.XAttrEnabled, err = confMap.FetchOptionValueBool("Agent", "XAttrEnabled")
   604  	if nil != err {
   605  		logFatal(err)
   606  	}
   607  
   608  	globals.config.EntryDuration, err = confMap.FetchOptionValueDuration("Agent", "EntryDuration")
   609  	if nil != err {
   610  		logFatal(err)
   611  	}
   612  
   613  	globals.config.AttrDuration, err = confMap.FetchOptionValueDuration("Agent", "AttrDuration")
   614  	if nil != err {
   615  		logFatal(err)
   616  	}
   617  
   618  	globals.config.AttrBlockSize, err = confMap.FetchOptionValueUint64("Agent", "AttrBlockSize")
   619  	if nil != err {
   620  		logFatal(err)
   621  	}
   622  	if (0 == globals.config.AttrBlockSize) || (math.MaxUint32 < globals.config.AttrBlockSize) {
   623  		logFatalf("AttrBlockSize must be non-zero and fit in a uint32")
   624  	}
   625  
   626  	globals.config.ReaddirMaxEntries, err = confMap.FetchOptionValueUint64("Agent", "ReaddirMaxEntries")
   627  	if nil != err {
   628  		logFatal(err)
   629  	}
   630  
   631  	globals.config.FUSEMaxBackground, err = confMap.FetchOptionValueUint16("Agent", "FUSEMaxBackground")
   632  	if nil != err {
   633  		logFatal(err)
   634  	}
   635  
   636  	globals.config.FUSECongestionThreshhold, err = confMap.FetchOptionValueUint16("Agent", "FUSECongestionThreshhold")
   637  	if nil != err {
   638  		logFatal(err)
   639  	}
   640  
   641  	globals.config.FUSEMaxWrite, err = confMap.FetchOptionValueUint32("Agent", "FUSEMaxWrite")
   642  	if nil != err {
   643  		logFatal(err)
   644  	}
   645  
   646  	globals.config.RetryRPCDeadlineIO, err = confMap.FetchOptionValueDuration("Agent", "RetryRPCDeadlineIO")
   647  	if nil != err {
   648  		logFatal(err)
   649  	}
   650  
   651  	globals.config.RetryRPCKeepAlivePeriod, err = confMap.FetchOptionValueDuration("Agent", "RetryRPCKeepAlivePeriod")
   652  	if nil != err {
   653  		logFatal(err)
   654  	}
   655  
   656  	configJSONified = utils.JSONify(globals.config, true)
   657  
   658  	logInfof("\n%s", configJSONified)
   659  
   660  	globals.entryValidSec, globals.entryValidNSec = nsToUnixTime(uint64(globals.config.EntryDuration))
   661  	globals.attrValidSec, globals.attrValidNSec = nsToUnixTime(uint64(globals.config.AttrDuration))
   662  
   663  	defaultTransport, ok = http.DefaultTransport.(*http.Transport)
   664  	if !ok {
   665  		log.Fatalf("http.DefaultTransport not a *http.Transport")
   666  	}
   667  
   668  	customTransport = &http.Transport{ // Up-to-date as of Golang 1.11
   669  		Proxy:                  defaultTransport.Proxy,
   670  		DialContext:            defaultTransport.DialContext,
   671  		Dial:                   defaultTransport.Dial,
   672  		DialTLS:                defaultTransport.DialTLS,
   673  		TLSClientConfig:        defaultTransport.TLSClientConfig,
   674  		TLSHandshakeTimeout:    globals.config.SwiftTimeout,
   675  		DisableKeepAlives:      false,
   676  		DisableCompression:     defaultTransport.DisableCompression,
   677  		MaxIdleConns:           int(globals.config.SwiftConnectionPoolSize),
   678  		MaxIdleConnsPerHost:    int(globals.config.SwiftConnectionPoolSize),
   679  		MaxConnsPerHost:        int(globals.config.SwiftConnectionPoolSize),
   680  		IdleConnTimeout:        globals.config.SwiftTimeout,
   681  		ResponseHeaderTimeout:  globals.config.SwiftTimeout,
   682  		ExpectContinueTimeout:  globals.config.SwiftTimeout,
   683  		TLSNextProto:           defaultTransport.TLSNextProto,
   684  		ProxyConnectHeader:     defaultTransport.ProxyConnectHeader,
   685  		MaxResponseHeaderBytes: defaultTransport.MaxResponseHeaderBytes,
   686  	}
   687  
   688  	globals.httpClient = &http.Client{
   689  		Transport: customTransport,
   690  		Timeout:   globals.config.SwiftTimeout,
   691  	}
   692  
   693  	globals.retryDelay = make([]retryDelayElementStruct, globals.config.SwiftRetryLimit)
   694  
   695  	nextRetryDelay = globals.config.SwiftRetryDelay
   696  
   697  	for retryIndex = 0; retryIndex < globals.config.SwiftRetryLimit; retryIndex++ {
   698  		globals.retryDelay[retryIndex].nominal = nextRetryDelay
   699  		globals.retryDelay[retryIndex].variance = nextRetryDelay * time.Duration(globals.config.SwiftRetryDelayVariance) / time.Duration(100)
   700  		nextRetryDelay = time.Duration(float64(nextRetryDelay) * globals.config.SwiftRetryExpBackoff)
   701  	}
   702  
   703  	globals.authPlugInControl = nil
   704  
   705  	globals.swiftAuthWaitGroup = nil
   706  	globals.swiftAuthToken = ""
   707  	globals.swiftStorageURL = ""
   708  
   709  	globals.fissionErrChan = make(chan error)
   710  
   711  	globals.jrpcLastID = 1
   712  
   713  	globals.fileInodeMap = make(map[inode.InodeNumber]*fileInodeStruct)
   714  
   715  	globals.fileInodeDirtyList = list.New()
   716  
   717  	globals.fileInodeDirtyLogSegmentChan = make(chan struct{}, globals.config.DirtyLogSegmentLimit)
   718  
   719  	for fileInodeDirtyLogSegmentChanIndex = 0; fileInodeDirtyLogSegmentChanIndex < globals.config.DirtyLogSegmentLimit; fileInodeDirtyLogSegmentChanIndex++ {
   720  		globals.fileInodeDirtyLogSegmentChan <- struct{}{}
   721  	}
   722  
   723  	globals.unleasedFileInodeCacheLRU = list.New()
   724  	globals.sharedLeaseFileInodeCacheLRU = list.New()
   725  	globals.exclusiveLeaseFileInodeCacheLRU = list.New()
   726  
   727  	globals.fhToInodeNumberMap = make(map[uint64]uint64)
   728  	globals.inodeNumberToFHMap = make(map[uint64]fhSetType)
   729  
   730  	globals.lastFH = 0
   731  
   732  	globals.logSegmentCacheMap = make(map[logSegmentCacheElementKeyStruct]*logSegmentCacheElementStruct)
   733  	globals.logSegmentCacheLRU = list.New()
   734  
   735  	globals.metrics = &metricsStruct{}
   736  	globals.stats = &statsStruct{}
   737  
   738  	bucketstats.Register("PFSAgent", "", globals.stats)
   739  }
   740  
   741  func uninitializeGlobals() {
   742  	bucketstats.UnRegister("PFSAgent", "")
   743  
   744  	globals.logFile = nil
   745  	globals.retryRPCPublicIPAddr = ""
   746  	globals.retryRPCPort = 0
   747  	globals.retryRPCClient = nil
   748  	globals.rootCAx509CertificatePEM = []byte{}
   749  	globals.entryValidSec = 0
   750  	globals.entryValidNSec = 0
   751  	globals.attrValidSec = 0
   752  	globals.attrValidNSec = 0
   753  	globals.httpServer = nil
   754  	globals.httpClient = nil
   755  	globals.retryDelay = nil
   756  	globals.authPlugInControl = nil
   757  	globals.swiftAuthWaitGroup = nil
   758  	globals.swiftAuthToken = ""
   759  	globals.swiftStorageURL = ""
   760  	globals.fissionErrChan = nil
   761  	globals.fissionVolume = nil
   762  	globals.fuseConn = nil
   763  	globals.jrpcLastID = 0
   764  	globals.fileInodeMap = nil
   765  	globals.fileInodeDirtyList = nil
   766  	globals.fileInodeDirtyLogSegmentChan = nil
   767  	globals.unleasedFileInodeCacheLRU = nil       // TODO: Obsolete this
   768  	globals.sharedLeaseFileInodeCacheLRU = nil    // TODO: Obsolete this
   769  	globals.exclusiveLeaseFileInodeCacheLRU = nil // TODO: Obsolete this
   770  	globals.fhToInodeNumberMap = nil
   771  	globals.inodeNumberToFHMap = nil
   772  	globals.lastFH = 0
   773  	globals.logSegmentCacheMap = nil
   774  	globals.logSegmentCacheLRU = nil
   775  	globals.metrics = nil
   776  	globals.stats = nil
   777  }