github.com/rohankumardubey/proxyfs@v0.0.0-20210108201508-653efa9ab00e/inode/config.go (about) 1 package inode 2 3 import ( 4 "fmt" 5 "sync" 6 "time" 7 "unsafe" 8 9 "github.com/swiftstack/cstruct" 10 "github.com/swiftstack/sortedmap" 11 12 "github.com/swiftstack/ProxyFS/blunder" 13 "github.com/swiftstack/ProxyFS/conf" 14 "github.com/swiftstack/ProxyFS/headhunter" 15 "github.com/swiftstack/ProxyFS/logger" 16 "github.com/swiftstack/ProxyFS/swiftclient" 17 "github.com/swiftstack/ProxyFS/trackedlock" 18 "github.com/swiftstack/ProxyFS/transitions" 19 ) 20 21 type readCacheKeyStruct struct { 22 volumeName string 23 logSegmentNumber uint64 24 cacheLineTag uint64 // LogSegment offset / readCacheLineSize 25 } 26 27 type readCacheElementStruct struct { 28 readCacheKey readCacheKeyStruct 29 next *readCacheElementStruct // nil if MRU element of volumeGroupStruct.readCache 30 prev *readCacheElementStruct // nil if LRU element of volumeGroupStruct.readCache 31 cacheLine []byte 32 } 33 34 type volumeGroupStruct struct { 35 trackedlock.Mutex 36 name string 37 volumeMap map[string]*volumeStruct // key == volumeStruct.volumeName 38 numServed uint64 39 virtualIPAddr string 40 activePeerPrivateIPAddr string 41 readCacheLineSize uint64 42 readCacheWeight uint64 43 readCacheLineCount uint64 44 readCache map[readCacheKeyStruct]*readCacheElementStruct 45 readCacheMRU *readCacheElementStruct 46 readCacheLRU *readCacheElementStruct 47 } 48 49 type physicalContainerLayoutStruct struct { 50 name string 51 containerStoragePolicy string // [<PhysicalContainerLayout>]ContainerStoragePolicy 52 containerNamePrefix string // [<PhysicalContainerLayout>]ContainerNamePrefix 53 containerNameSlice []string // == slice of current PhysicalContainers for this PhysicalContainerLayout 54 // Note: all prefixed by containerNamePrefix 55 containersPerPeer uint64 // [<PhysicalContainerLayout>]ContainersPerPeer 56 maxObjectsPerContainer uint64 // [<PhysicalContainerLayout>]MaxObjectsPerContainer 57 containerNameSliceNextIndex uint64 // == next index in nameSlice 58 containerNameSliceLoopCount uint64 // == number of times looped through nameSlice 59 // Note: if 0 == (containerNameSliceLoopCount mod maxObjectsPerContainer) 60 // then we need to re-provision containerNameSlice 61 } 62 63 type volumeStruct struct { 64 trackedlock.Mutex 65 volumeGroup *volumeGroupStruct 66 served bool 67 fsid uint64 68 volumeName string 69 accountName string 70 maxEntriesPerDirNode uint64 71 maxExtentsPerFileNode uint64 72 defaultPhysicalContainerLayout *physicalContainerLayoutStruct 73 maxFlushSize uint64 74 headhunterVolumeHandle headhunter.VolumeHandle 75 inodeCache sortedmap.LLRBTree // key == InodeNumber; value == *inMemoryInodeStruct 76 inodeCacheStopChan chan struct{} 77 inodeCacheWG sync.WaitGroup 78 inodeCacheLRUHead *inMemoryInodeStruct 79 inodeCacheLRUTail *inMemoryInodeStruct 80 inodeCacheLRUItems uint64 81 inodeCacheLRUMaxBytes uint64 82 inodeCacheLRUTicker *time.Ticker 83 inodeCacheLRUTickerInterval time.Duration 84 snapShotPolicy *snapShotPolicyStruct 85 } 86 87 const ( 88 defaultNoWriteErrno = blunder.NoSpaceError 89 defaultNoWriteErrnoString = "ENOSPC" 90 defaultReadOnlyErrno = blunder.ReadOnlyError 91 defaultReadOnlyErrnoString = "EROFS" 92 ) 93 94 type globalsStruct struct { 95 trackedlock.Mutex 96 whoAmI string 97 myPrivateIPAddr string 98 dirEntryCache sortedmap.BPlusTreeCache 99 dirEntryCachePriorCacheHits uint64 100 dirEntryCachePriorCacheMisses uint64 101 fileExtentMapCache sortedmap.BPlusTreeCache 102 fileExtentMapCachePriorCacheHits uint64 103 fileExtentMapCachePriorCacheMisses uint64 104 volumeGroupMap map[string]*volumeGroupStruct // key == volumeGroupStruct.name 105 volumeMap map[string]*volumeStruct // key == volumeStruct.volumeName 106 accountMap map[string]*volumeStruct // key == volumeStruct.accountName 107 fileExtentStructSize uint64 // pre-calculated size of cstruct-packed fileExtentStruct 108 supportedOnDiskInodeVersions map[Version]struct{} // key == on disk inode version 109 corruptionDetectedTrueBuf []byte // holds serialized CorruptionDetected == true 110 corruptionDetectedFalseBuf []byte // holds serialized CorruptionDetected == false 111 versionV1Buf []byte // holds serialized Version == V1 112 inodeRecDefaultPreambleBuf []byte // holds concatenated corruptionDetectedFalseBuf & versionV1Buf 113 inodeSize uint64 // size of in-memory inode struct 114 openLogSegmentLRUHead *inFlightLogSegmentStruct 115 openLogSegmentLRUTail *inFlightLogSegmentStruct 116 openLogSegmentLRUItems uint64 117 noWriteThresholdErrno blunder.FsError // either blunder.NotPermError or blunder.ReadOnlyError or blunder.NoSpaceError 118 noWriteThresholdErrnoString string // either "EPERM" or "EROFS" or "ENOSPC" 119 readOnlyThresholdErrno blunder.FsError // either blunder.NotPermError or blunder.ReadOnlyError or blunder.NoSpaceError 120 readOnlyThresholdErrnoString string // either "EPERM" or "EROFS" or "ENOSPC" 121 rwMode RWModeType // One of RWMode{Normal|NoWrite|ReadOnly} 122 } 123 124 var globals globalsStruct 125 126 func init() { 127 transitions.Register("inode", &globals) 128 } 129 130 func (dummy *globalsStruct) Up(confMap conf.ConfMap) (err error) { 131 var ( 132 corruptionDetectedFalse = CorruptionDetected(false) 133 corruptionDetectedTrue = CorruptionDetected(true) 134 dirEntryCacheEvictHighLimit uint64 135 dirEntryCacheEvictLowLimit uint64 136 fileExtentMapEvictHighLimit uint64 137 fileExtentMapEvictLowLimit uint64 138 ok bool 139 peerName string 140 peerNames []string 141 peerPrivateIPAddr string 142 peerPrivateIPAddrMap map[string]string 143 tempInode inMemoryInodeStruct 144 versionV1 = Version(V1) 145 ) 146 147 peerPrivateIPAddrMap = make(map[string]string) 148 149 peerNames, err = confMap.FetchOptionValueStringSlice("Cluster", "Peers") 150 if nil != err { 151 return 152 } 153 154 for _, peerName = range peerNames { 155 peerPrivateIPAddr, err = confMap.FetchOptionValueString("Peer:"+peerName, "PrivateIPAddr") 156 if nil != err { 157 return 158 } 159 160 peerPrivateIPAddrMap[peerName] = peerPrivateIPAddr 161 } 162 163 globals.whoAmI, err = confMap.FetchOptionValueString("Cluster", "WhoAmI") 164 if nil != err { 165 return 166 } 167 globals.myPrivateIPAddr, ok = peerPrivateIPAddrMap[globals.whoAmI] 168 if !ok { 169 err = fmt.Errorf("Cluster.WhoAmI (\"%v\") not in Cluster.Peers list", globals.whoAmI) 170 return 171 } 172 173 dirEntryCacheEvictLowLimit, err = confMap.FetchOptionValueUint64("FSGlobals", "DirEntryCacheEvictLowLimit") 174 if nil != err { 175 return 176 } 177 dirEntryCacheEvictHighLimit, err = confMap.FetchOptionValueUint64("FSGlobals", "DirEntryCacheEvictHighLimit") 178 if nil != err { 179 return 180 } 181 182 globals.dirEntryCache = sortedmap.NewBPlusTreeCache(dirEntryCacheEvictLowLimit, dirEntryCacheEvictHighLimit) 183 184 globals.dirEntryCachePriorCacheHits = 0 185 globals.dirEntryCachePriorCacheMisses = 0 186 187 fileExtentMapEvictLowLimit, err = confMap.FetchOptionValueUint64("FSGlobals", "FileExtentMapEvictLowLimit") 188 if nil != err { 189 return 190 } 191 fileExtentMapEvictHighLimit, err = confMap.FetchOptionValueUint64("FSGlobals", "FileExtentMapEvictHighLimit") 192 if nil != err { 193 return 194 } 195 196 globals.fileExtentMapCache = sortedmap.NewBPlusTreeCache(fileExtentMapEvictLowLimit, fileExtentMapEvictHighLimit) 197 198 globals.fileExtentMapCachePriorCacheHits = 0 199 globals.fileExtentMapCachePriorCacheMisses = 0 200 201 globals.volumeGroupMap = make(map[string]*volumeGroupStruct) 202 globals.volumeMap = make(map[string]*volumeStruct) 203 globals.accountMap = make(map[string]*volumeStruct) 204 205 globals.inodeSize = uint64(unsafe.Sizeof(tempInode)) 206 207 globals.openLogSegmentLRUHead = nil 208 globals.openLogSegmentLRUTail = nil 209 globals.openLogSegmentLRUItems = 0 210 211 globals.fileExtentStructSize, _, err = cstruct.Examine(fileExtentStruct{}) 212 if nil != err { 213 return 214 } 215 216 globals.supportedOnDiskInodeVersions = make(map[Version]struct{}) 217 218 globals.supportedOnDiskInodeVersions[V1] = struct{}{} 219 220 globals.corruptionDetectedTrueBuf, err = cstruct.Pack(corruptionDetectedTrue, cstruct.LittleEndian) 221 if nil != err { 222 return 223 } 224 globals.corruptionDetectedFalseBuf, err = cstruct.Pack(corruptionDetectedFalse, cstruct.LittleEndian) 225 if nil != err { 226 return 227 } 228 globals.versionV1Buf, err = cstruct.Pack(versionV1, cstruct.LittleEndian) 229 if nil != err { 230 return 231 } 232 233 globals.inodeRecDefaultPreambleBuf = make([]byte, 0, len(globals.corruptionDetectedFalseBuf)+len(globals.versionV1Buf)) 234 globals.inodeRecDefaultPreambleBuf = append(globals.inodeRecDefaultPreambleBuf, globals.corruptionDetectedFalseBuf...) 235 globals.inodeRecDefaultPreambleBuf = append(globals.inodeRecDefaultPreambleBuf, globals.versionV1Buf...) 236 237 swiftclient.SetStarvationCallbackFunc(chunkedPutConnectionPoolStarvationCallback) 238 239 globals.rwMode = RWModeNormal 240 241 err = nil 242 return 243 } 244 245 func (dummy *globalsStruct) VolumeGroupCreated(confMap conf.ConfMap, volumeGroupName string, activePeer string, virtualIPAddr string) (err error) { 246 var ( 247 ok bool 248 volumeGroup *volumeGroupStruct 249 volumeGroupSectionName string 250 ) 251 252 volumeGroup = &volumeGroupStruct{ 253 name: volumeGroupName, 254 volumeMap: make(map[string]*volumeStruct), 255 numServed: 0, 256 readCacheLineCount: 0, 257 readCache: make(map[readCacheKeyStruct]*readCacheElementStruct), 258 readCacheMRU: nil, 259 readCacheLRU: nil, 260 } 261 262 volumeGroupSectionName = "VolumeGroup:" + volumeGroupName 263 264 volumeGroup.virtualIPAddr, err = confMap.FetchOptionValueString(volumeGroupSectionName, "VirtualIPAddr") 265 if nil != err { 266 if nil == confMap.VerifyOptionValueIsEmpty(volumeGroupSectionName, "VirtualIPAddr") { 267 volumeGroup.virtualIPAddr = "" 268 } else { 269 return 270 } 271 } 272 273 if "" == activePeer { 274 volumeGroup.activePeerPrivateIPAddr = "" 275 } else { 276 volumeGroup.activePeerPrivateIPAddr, err = confMap.FetchOptionValueString("Peer:"+activePeer, "PrivateIPAddr") 277 if nil != err { 278 return 279 } 280 } 281 282 volumeGroup.readCacheLineSize, err = confMap.FetchOptionValueUint64(volumeGroupSectionName, "ReadCacheLineSize") 283 if nil != err { 284 return 285 } 286 287 volumeGroup.readCacheWeight, err = confMap.FetchOptionValueUint64(volumeGroupSectionName, "ReadCacheWeight") 288 if nil != err { 289 return 290 } 291 if volumeGroup.readCacheWeight <= 0 { 292 logger.Warnf("Section '%s' for VolumeGroup '%s' ReadCacheWeight %d is <= 0; changing to 1", 293 volumeGroupSectionName, volumeGroupName, volumeGroup.readCacheWeight) 294 volumeGroup.readCacheWeight = 1 295 } 296 297 globals.Lock() 298 299 _, ok = globals.volumeGroupMap[volumeGroupName] 300 if ok { 301 globals.Unlock() 302 err = fmt.Errorf("inode.VolumeGroupCreated() called for preexisting VolumeGroup (%s)", volumeGroupName) 303 return 304 } 305 306 globals.volumeGroupMap[volumeGroupName] = volumeGroup 307 308 globals.Unlock() 309 310 err = nil 311 return 312 } 313 314 func (dummy *globalsStruct) VolumeGroupMoved(confMap conf.ConfMap, volumeGroupName string, activePeer string, virtualIPAddr string) (err error) { 315 var ( 316 ok bool 317 volumeGroup *volumeGroupStruct 318 ) 319 320 globals.Lock() 321 322 volumeGroup, ok = globals.volumeGroupMap[volumeGroupName] 323 if !ok { 324 globals.Unlock() 325 err = fmt.Errorf("inode.VolumeGroupMoved() called for nonexistent VolumeGroup (%s)", volumeGroupName) 326 return 327 } 328 329 volumeGroup.Lock() 330 331 if "" == activePeer { 332 volumeGroup.activePeerPrivateIPAddr = "" 333 } else { 334 volumeGroup.activePeerPrivateIPAddr, err = confMap.FetchOptionValueString("Peer:"+activePeer, "PrivateIPAddr") 335 if nil != err { 336 volumeGroup.Unlock() 337 globals.Unlock() 338 return 339 } 340 } 341 342 // Note that VirtualIPAddr, ReadCacheLineSize, & ReadCacheWeight are not reloaded 343 344 volumeGroup.Unlock() 345 globals.Unlock() 346 347 err = nil 348 return 349 } 350 351 func (dummy *globalsStruct) VolumeGroupDestroyed(confMap conf.ConfMap, volumeGroupName string) (err error) { 352 var ( 353 ok bool 354 volumeGroup *volumeGroupStruct 355 ) 356 357 globals.Lock() 358 359 volumeGroup, ok = globals.volumeGroupMap[volumeGroupName] 360 if !ok { 361 globals.Unlock() 362 err = fmt.Errorf("inode.VolumeGroupDestroyed() called for nonexistent VolumeGroup (%s)", volumeGroupName) 363 return 364 } 365 366 volumeGroup.Lock() 367 368 if 0 != len(volumeGroup.volumeMap) { 369 volumeGroup.Unlock() 370 globals.Unlock() 371 err = fmt.Errorf("inode.VolumeGroupDestroyed() called for non-empty VolumeGroup (%s)", volumeGroupName) 372 return 373 } 374 375 delete(globals.volumeGroupMap, volumeGroupName) 376 377 volumeGroup.Unlock() 378 globals.Unlock() 379 380 err = nil 381 return 382 } 383 384 func (dummy *globalsStruct) VolumeCreated(confMap conf.ConfMap, volumeName string, volumeGroupName string) (err error) { 385 var ( 386 ok bool 387 volumeGroup *volumeGroupStruct 388 volumeSectionName string 389 ) 390 391 volume := &volumeStruct{volumeName: volumeName, served: false} 392 393 volumeSectionName = "Volume:" + volumeName 394 395 volume.fsid, err = confMap.FetchOptionValueUint64(volumeSectionName, "FSID") 396 if nil != err { 397 return 398 } 399 400 volume.accountName, err = confMap.FetchOptionValueString(volumeSectionName, "AccountName") 401 if nil != err { 402 return 403 } 404 405 globals.Lock() 406 407 _, ok = globals.volumeMap[volumeName] 408 if ok { 409 globals.Unlock() 410 err = fmt.Errorf("inode.VolumeCreated() called for preexiting Volume (%s)", volumeName) 411 return 412 } 413 414 _, ok = globals.accountMap[volume.accountName] 415 if ok { 416 globals.Unlock() 417 err = fmt.Errorf("inode.VolumeCreated() called for preexiting Account (%s)", volume.accountName) 418 return 419 } 420 421 volumeGroup, ok = globals.volumeGroupMap[volumeGroupName] 422 if !ok { 423 globals.Unlock() 424 err = fmt.Errorf("inode.VolumeCreated() called for Volume (%s) to be added to nonexistent VolumeGroup (%s)", volumeName, volumeGroupName) 425 return 426 } 427 428 volumeGroup.Lock() 429 430 _, ok = volumeGroup.volumeMap[volumeName] 431 if ok { 432 volumeGroup.Unlock() 433 globals.Unlock() 434 err = fmt.Errorf("inode.VolumeCreated() called for preexiting Volume (%s) to be added to VolumeGroup (%s)", volumeName, volumeGroupName) 435 return 436 } 437 438 volume.volumeGroup = volumeGroup 439 volumeGroup.volumeMap[volumeName] = volume 440 globals.volumeMap[volumeName] = volume 441 globals.accountMap[volume.accountName] = volume 442 443 volumeGroup.Unlock() 444 globals.Unlock() 445 446 err = nil 447 return 448 } 449 450 func (dummy *globalsStruct) VolumeMoved(confMap conf.ConfMap, volumeName string, volumeGroupName string) (err error) { 451 var ( 452 newVolumeGroup *volumeGroupStruct 453 ok bool 454 oldVolumeGroup *volumeGroupStruct 455 volume *volumeStruct 456 ) 457 458 globals.Lock() 459 460 volume, ok = globals.volumeMap[volumeName] 461 if !ok { 462 globals.Unlock() 463 err = fmt.Errorf("inode.VolumeMoved() called for nonexistent Volume (%s)", volumeName) 464 return 465 } 466 467 if volume.served { 468 globals.Unlock() 469 err = fmt.Errorf("inode.VolumeMoved() called for Volume (%s) being actively served", volumeName) 470 return 471 } 472 473 newVolumeGroup, ok = globals.volumeGroupMap[volumeGroupName] 474 if !ok { 475 globals.Unlock() 476 err = fmt.Errorf("inode.VolumeMoved() called for Volume (%s) to be moved to nonexistent VolumeGroup (%s)", volumeName, volumeGroupName) 477 return 478 } 479 480 newVolumeGroup.Lock() 481 482 _, ok = newVolumeGroup.volumeMap[volumeName] 483 if ok { 484 newVolumeGroup.Unlock() 485 globals.Unlock() 486 err = fmt.Errorf("inode.VolumeMoved() called for Volume (%s) to be moved to VolumeGroup (%s) already containing the Volume", volumeName, volumeGroupName) 487 return 488 } 489 490 oldVolumeGroup = volume.volumeGroup 491 492 oldVolumeGroup.Lock() 493 494 delete(oldVolumeGroup.volumeMap, volumeName) 495 newVolumeGroup.volumeMap[volumeName] = volume 496 volume.volumeGroup = newVolumeGroup 497 498 // Note that FSID & AccountName are not reloaded 499 500 oldVolumeGroup.Unlock() 501 newVolumeGroup.Unlock() 502 globals.Unlock() 503 504 err = nil 505 return 506 } 507 508 func (dummy *globalsStruct) VolumeDestroyed(confMap conf.ConfMap, volumeName string) (err error) { 509 var ( 510 ok bool 511 volume *volumeStruct 512 ) 513 514 globals.Lock() 515 516 volume, ok = globals.volumeMap[volumeName] 517 if !ok { 518 globals.Unlock() 519 err = fmt.Errorf("inode.VolumeDestroyed() called for nonexistent Volume (%s)", volumeName) 520 return 521 } 522 523 if volume.served { 524 globals.Unlock() 525 err = fmt.Errorf("inode.VolumeDestroyed() called for Volume (%s) being actively served", volumeName) 526 return 527 } 528 529 volume.volumeGroup.Lock() 530 531 delete(volume.volumeGroup.volumeMap, volumeName) 532 delete(globals.volumeMap, volumeName) 533 delete(globals.accountMap, volume.accountName) 534 535 volume.volumeGroup.Unlock() 536 globals.Unlock() 537 538 err = nil 539 return 540 } 541 542 func (dummy *globalsStruct) ServeVolume(confMap conf.ConfMap, volumeName string) (err error) { 543 var ( 544 defaultPhysicalContainerLayout *physicalContainerLayoutStruct 545 defaultPhysicalContainerLayoutName string 546 defaultPhysicalContainerLayoutSectionName string 547 ok bool 548 volume *volumeStruct 549 volumeSectionName string 550 ) 551 552 volumeSectionName = "Volume:" + volumeName 553 554 globals.Lock() 555 556 volume, ok = globals.volumeMap[volumeName] 557 if !ok { 558 globals.Unlock() 559 err = fmt.Errorf("inode.ServeVolume() called for nonexistent Volume (%s)", volumeName) 560 return 561 } 562 if volume.served { 563 globals.Unlock() 564 err = fmt.Errorf("inode.ServeVolume() called for Volume (%s) already being served", volumeName) 565 return 566 } 567 568 volume.maxEntriesPerDirNode, err = confMap.FetchOptionValueUint64(volumeSectionName, "MaxEntriesPerDirNode") 569 if nil != err { 570 globals.Unlock() 571 return 572 } 573 volume.maxExtentsPerFileNode, err = confMap.FetchOptionValueUint64(volumeSectionName, "MaxExtentsPerFileNode") 574 if nil != err { 575 globals.Unlock() 576 return 577 } 578 defaultPhysicalContainerLayoutName, err = confMap.FetchOptionValueString(volumeSectionName, "DefaultPhysicalContainerLayout") 579 if nil != err { 580 globals.Unlock() 581 return 582 } 583 584 defaultPhysicalContainerLayout = &physicalContainerLayoutStruct{ 585 name: defaultPhysicalContainerLayoutName, 586 containerNameSliceNextIndex: 0, 587 containerNameSliceLoopCount: 0, 588 } 589 590 defaultPhysicalContainerLayoutSectionName = "PhysicalContainerLayout:" + defaultPhysicalContainerLayoutName 591 592 defaultPhysicalContainerLayout.containerStoragePolicy, err = confMap.FetchOptionValueString(defaultPhysicalContainerLayoutSectionName, "ContainerStoragePolicy") 593 if nil != err { 594 globals.Unlock() 595 return 596 } 597 defaultPhysicalContainerLayout.containerNamePrefix, err = confMap.FetchOptionValueString(defaultPhysicalContainerLayoutSectionName, "ContainerNamePrefix") 598 if nil != err { 599 globals.Unlock() 600 return 601 } 602 defaultPhysicalContainerLayout.containersPerPeer, err = confMap.FetchOptionValueUint64(defaultPhysicalContainerLayoutSectionName, "ContainersPerPeer") 603 if nil != err { 604 globals.Unlock() 605 return 606 } 607 defaultPhysicalContainerLayout.maxObjectsPerContainer, err = confMap.FetchOptionValueUint64(defaultPhysicalContainerLayoutSectionName, "MaxObjectsPerContainer") 608 if nil != err { 609 globals.Unlock() 610 return 611 } 612 613 defaultPhysicalContainerLayout.containerNameSlice = make([]string, defaultPhysicalContainerLayout.containersPerPeer) 614 615 volume.defaultPhysicalContainerLayout = defaultPhysicalContainerLayout 616 617 volume.maxFlushSize, err = confMap.FetchOptionValueUint64(volumeSectionName, "MaxFlushSize") 618 if nil != err { 619 globals.Unlock() 620 return 621 } 622 623 volume.headhunterVolumeHandle, err = headhunter.FetchVolumeHandle(volume.volumeName) 624 if nil != err { 625 globals.Unlock() 626 return 627 } 628 629 volume.headhunterVolumeHandle.RegisterForEvents(volume) 630 631 volume.inodeCache = sortedmap.NewLLRBTree(compareInodeNumber, volume) 632 volume.inodeCacheStopChan = make(chan struct{}, 0) 633 volume.inodeCacheLRUHead = nil 634 volume.inodeCacheLRUTail = nil 635 volume.inodeCacheLRUItems = 0 636 637 err = startInodeCacheDiscard(confMap, volume, volumeSectionName) 638 if nil != err { 639 globals.Unlock() 640 return 641 } 642 643 volume.volumeGroup.Lock() 644 645 volume.served = true 646 volume.volumeGroup.numServed++ 647 648 volume.volumeGroup.Unlock() 649 650 globals.Unlock() 651 652 err = adoptVolumeGroupReadCacheParameters(confMap) 653 654 return // err from call to adoptVolumeGroupReadCacheParameters() is fine to return here 655 } 656 657 func (dummy *globalsStruct) UnserveVolume(confMap conf.ConfMap, volumeName string) (err error) { 658 var ( 659 ok bool 660 volume *volumeStruct 661 ) 662 663 globals.Lock() 664 665 volume, ok = globals.volumeMap[volumeName] 666 if !ok { 667 globals.Unlock() 668 err = fmt.Errorf("inode.UnserveVolume() called for nonexistent Volume (%s)", volumeName) 669 return 670 } 671 if !volume.served { 672 globals.Unlock() 673 err = fmt.Errorf("inode.UnserveVolume() called for Volume (%s) not being served", volumeName) 674 return 675 } 676 677 stopInodeCacheDiscard(volume) 678 679 volume.inodeCache = nil 680 volume.inodeCacheStopChan = nil 681 volume.inodeCacheLRUHead = nil 682 volume.inodeCacheLRUTail = nil 683 volume.inodeCacheLRUItems = 0 684 685 volume.headhunterVolumeHandle.UnregisterForEvents(volume) 686 687 volume.volumeGroup.Lock() 688 689 volume.served = false 690 volume.volumeGroup.numServed-- 691 692 volume.volumeGroup.Unlock() 693 globals.Unlock() 694 695 err = adoptVolumeGroupReadCacheParameters(confMap) 696 697 return // err from call to adoptVolumeGroupReadCacheParameters() is fine to return here 698 } 699 700 func (dummy *globalsStruct) VolumeToBeUnserved(confMap conf.ConfMap, volumeName string) (err error) { 701 err = nil 702 return 703 } 704 705 func (dummy *globalsStruct) SignaledStart(confMap conf.ConfMap) (err error) { 706 var ( 707 volume *volumeStruct 708 ) 709 710 for _, volume = range globals.volumeMap { 711 if volume.served && (nil != volume.snapShotPolicy) { 712 volume.snapShotPolicy.down() 713 volume.snapShotPolicy = nil 714 } 715 } 716 717 err = nil 718 return 719 } 720 721 func (dummy *globalsStruct) SignaledFinish(confMap conf.ConfMap) (err error) { 722 var ( 723 swiftReconNoWriteErrno string 724 swiftReconReadOnlyErrno string 725 volume *volumeStruct 726 ) 727 728 swiftReconNoWriteErrno, err = confMap.FetchOptionValueString("SwiftClient", "SwiftReconNoWriteErrno") 729 if nil == err { 730 switch swiftReconNoWriteErrno { 731 case "EPERM": 732 globals.noWriteThresholdErrno = blunder.NotPermError 733 globals.noWriteThresholdErrnoString = "EPERM" 734 case "EROFS": 735 globals.noWriteThresholdErrno = blunder.ReadOnlyError 736 globals.noWriteThresholdErrnoString = "EROFS" 737 case "ENOSPC": 738 globals.noWriteThresholdErrno = blunder.NoSpaceError 739 globals.noWriteThresholdErrnoString = "ENOSPC" 740 default: 741 err = fmt.Errorf("[SwiftClient]SwiftReconReadOnlyErrno must be either EPERM or EROFS or ENOSPC") 742 return 743 } 744 } else { 745 logger.WarnfWithError(err, "Unable to fetch [SwiftClient]SwiftReconNoWriteErrno... defaulting to %s", defaultNoWriteErrno) 746 globals.noWriteThresholdErrno = defaultNoWriteErrno 747 globals.noWriteThresholdErrnoString = defaultNoWriteErrnoString 748 } 749 750 swiftReconReadOnlyErrno, err = confMap.FetchOptionValueString("SwiftClient", "SwiftReconReadOnlyErrno") 751 if nil == err { 752 switch swiftReconReadOnlyErrno { 753 case "EPERM": 754 globals.readOnlyThresholdErrno = blunder.NotPermError 755 globals.readOnlyThresholdErrnoString = "EPERM" 756 case "EROFS": 757 globals.readOnlyThresholdErrno = blunder.ReadOnlyError 758 globals.readOnlyThresholdErrnoString = "EROFS" 759 case "ENOSPC": 760 globals.readOnlyThresholdErrno = blunder.NoSpaceError 761 globals.readOnlyThresholdErrnoString = "ENOSPC" 762 default: 763 err = fmt.Errorf("[SwiftClient]SwiftReconReadOnlyErrno must be either EPERM or EROFS or ENOSPC") 764 return 765 } 766 } else { 767 logger.WarnfWithError(err, "Unable to fetch [SwiftClient]SwiftReconReadOnlyErrno... defaulting to %s", defaultReadOnlyErrno) 768 globals.readOnlyThresholdErrno = defaultReadOnlyErrno 769 globals.readOnlyThresholdErrnoString = defaultReadOnlyErrnoString 770 } 771 772 for _, volume = range globals.volumeMap { 773 if volume.served { 774 err = volume.loadSnapShotPolicy(confMap) 775 if nil != err { 776 return 777 } 778 if nil != volume.snapShotPolicy { 779 volume.snapShotPolicy.up() 780 } 781 } 782 } 783 784 err = nil 785 return 786 } 787 788 func (dummy *globalsStruct) Down(confMap conf.ConfMap) (err error) { 789 if 0 != len(globals.volumeGroupMap) { 790 err = fmt.Errorf("inode.Down() called with 0 != len(globals.volumeGroupMap") 791 return 792 } 793 if 0 != len(globals.volumeMap) { 794 err = fmt.Errorf("inode.Down() called with 0 != len(globals.volumeMap") 795 return 796 } 797 798 err = nil 799 return 800 }