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 }