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

     1  // Copyright (c) 2015-2021, NVIDIA CORPORATION.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package inode
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/swiftstack/ProxyFS/logger"
    10  	"github.com/swiftstack/ProxyFS/stats"
    11  	"github.com/swiftstack/sortedmap"
    12  )
    13  
    14  func (vS *volumeStruct) GetFSID() (fsid uint64) {
    15  	fsid = vS.fsid
    16  	return
    17  }
    18  
    19  func (vS *volumeStruct) SnapShotCreate(name string) (id uint64, err error) {
    20  	err = enforceRWMode(false)
    21  	if nil != err {
    22  		return
    23  	}
    24  
    25  	if ("." == name) || (".." == name) {
    26  		err = fmt.Errorf("SnapShot cannot be named either '.' or '..'")
    27  		return
    28  	}
    29  
    30  	vS.Lock()
    31  	id, err = vS.headhunterVolumeHandle.SnapShotCreateByInodeLayer(name)
    32  	vS.Unlock()
    33  	return
    34  }
    35  
    36  func (vS *volumeStruct) SnapShotDelete(id uint64) (err error) {
    37  	var (
    38  		found                               bool
    39  		keyAsInodeNumber                    InodeNumber
    40  		keyAsKey                            sortedmap.Key
    41  		indexWherePurgesAreToHappen         int
    42  		maxInodeNumberToPurgeFromInodeCache InodeNumber
    43  		minInodeNumberToPurgeFromInodeCache InodeNumber
    44  		ok                                  bool
    45  		valueAsValue                        sortedmap.Value
    46  		valueAsInodeStructPtr               *inMemoryInodeStruct
    47  	)
    48  
    49  	err = enforceRWMode(false)
    50  	if nil != err {
    51  		return
    52  	}
    53  
    54  	vS.Lock()
    55  	err = vS.headhunterVolumeHandle.SnapShotDeleteByInodeLayer(id)
    56  	if nil == err {
    57  		// Purge elements in inodeCache to avoid aliasing if/when SnapShotID is reused
    58  
    59  		minInodeNumberToPurgeFromInodeCache = InodeNumber(vS.headhunterVolumeHandle.SnapShotIDAndNonceEncode(id, uint64(0)))
    60  		maxInodeNumberToPurgeFromInodeCache = InodeNumber(vS.headhunterVolumeHandle.SnapShotIDAndNonceEncode(id+1, uint64(0)))
    61  
    62  		indexWherePurgesAreToHappen, found, err = vS.inodeCache.BisectRight(minInodeNumberToPurgeFromInodeCache)
    63  		if nil != err {
    64  			vS.Unlock()
    65  			err = fmt.Errorf("Volume %v InodeCache BisectRight() failed: %v", vS.volumeName, err)
    66  			logger.Error(err)
    67  			return
    68  		}
    69  
    70  		// If there is some InodeNumber at or beyond minInodeNumberToPurgeFromInodeCache, found == TRUE
    71  
    72  		for found {
    73  			keyAsKey, valueAsValue, ok, err = vS.inodeCache.GetByIndex(indexWherePurgesAreToHappen)
    74  			if nil != err {
    75  				vS.Unlock()
    76  				err = fmt.Errorf("Volume %v InodeCache GetByIndex() failed: %v", vS.volumeName, err)
    77  				logger.Error(err)
    78  				return
    79  			}
    80  
    81  			if !ok {
    82  				vS.Unlock()
    83  				return
    84  			}
    85  
    86  			keyAsInodeNumber, ok = keyAsKey.(InodeNumber)
    87  			if !ok {
    88  				vS.Unlock()
    89  				err = fmt.Errorf("Volume %v InodeCache GetByIndex() returned non-InodeNumber", vS.volumeName)
    90  				return
    91  			}
    92  
    93  			// Redefine found to indicate we've found an InodeCache entry to evict (used next iteration)
    94  
    95  			found = (keyAsInodeNumber < maxInodeNumberToPurgeFromInodeCache)
    96  
    97  			// func (vS *volumeStruct) inodeCacheDropWhileLocked(inode *inMemoryInodeStruct) (ok bool, err error)
    98  			if found {
    99  				valueAsInodeStructPtr, ok = valueAsValue.(*inMemoryInodeStruct)
   100  				if !ok {
   101  					vS.Unlock()
   102  					err = fmt.Errorf("Volume %v InodeCache GetByIndex() returned non-inMemoryInodeStructPtr", vS.volumeName)
   103  					return
   104  				}
   105  				ok, err = vS.inodeCacheDropWhileLocked(valueAsInodeStructPtr)
   106  				if nil != err {
   107  					vS.Unlock()
   108  					err = fmt.Errorf("Volume %v inodeCacheDropWhileLocked() failed: %v", vS.volumeName, err)
   109  					return
   110  				}
   111  				if !ok {
   112  					vS.Unlock()
   113  					err = fmt.Errorf("Volume %v inodeCacheDropWhileLocked() returned !ok", vS.volumeName)
   114  					return
   115  				}
   116  			}
   117  		}
   118  	}
   119  	vS.Unlock()
   120  	return
   121  }
   122  
   123  func (vS *volumeStruct) CheckpointCompleted() {
   124  	var (
   125  		dirEntryCacheHitsDelta        uint64
   126  		dirEntryCacheMissesDelta      uint64
   127  		dirEntryCacheStats            *sortedmap.BPlusTreeCacheStats
   128  		fileExtentMapCacheHitsDelta   uint64
   129  		fileExtentMapCacheMissesDelta uint64
   130  		fileExtentMapCacheStats       *sortedmap.BPlusTreeCacheStats
   131  	)
   132  
   133  	dirEntryCacheStats = globals.dirEntryCache.Stats()
   134  	fileExtentMapCacheStats = globals.fileExtentMapCache.Stats()
   135  
   136  	globals.Lock()
   137  
   138  	dirEntryCacheHitsDelta = dirEntryCacheStats.CacheHits - globals.dirEntryCachePriorCacheHits
   139  	dirEntryCacheMissesDelta = dirEntryCacheStats.CacheMisses - globals.dirEntryCachePriorCacheMisses
   140  
   141  	fileExtentMapCacheHitsDelta = fileExtentMapCacheStats.CacheHits - globals.fileExtentMapCachePriorCacheHits
   142  	fileExtentMapCacheMissesDelta = fileExtentMapCacheStats.CacheMisses - globals.fileExtentMapCachePriorCacheMisses
   143  
   144  	if 0 != dirEntryCacheHitsDelta {
   145  		stats.IncrementOperationsBy(&stats.DirEntryCacheHits, dirEntryCacheHitsDelta)
   146  		globals.dirEntryCachePriorCacheHits = dirEntryCacheStats.CacheHits
   147  	}
   148  	if 0 != dirEntryCacheMissesDelta {
   149  		stats.IncrementOperationsBy(&stats.DirEntryCacheMisses, dirEntryCacheMissesDelta)
   150  		globals.dirEntryCachePriorCacheMisses = dirEntryCacheStats.CacheMisses
   151  	}
   152  
   153  	if 0 != fileExtentMapCacheHitsDelta {
   154  		stats.IncrementOperationsBy(&stats.FileExtentMapCacheHits, fileExtentMapCacheHitsDelta)
   155  		globals.fileExtentMapCachePriorCacheHits = fileExtentMapCacheStats.CacheHits
   156  	}
   157  	if 0 != fileExtentMapCacheMissesDelta {
   158  		stats.IncrementOperationsBy(&stats.FileExtentMapCacheMisses, fileExtentMapCacheMissesDelta)
   159  		globals.fileExtentMapCachePriorCacheMisses = fileExtentMapCacheStats.CacheMisses
   160  	}
   161  
   162  	globals.Unlock()
   163  }