Skip to content

Commit

Permalink
Added [FSGlobals]CoalesceElementChunkSize to cap duration of each Coa…
Browse files Browse the repository at this point in the history
…lesce lock phase duration
  • Loading branch information
edmc-ss committed Dec 15, 2020
1 parent 6122a06 commit 1d9ad45
Show file tree
Hide file tree
Showing 26 changed files with 132 additions and 70 deletions.
1 change: 1 addition & 0 deletions CONFIGURING.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ For each of the keys supported, the following table will list whether or not its
| | TryLockBackoffMax | No | 50ms | Yes | No |
| | TryLockSerializationThreshhold | No | 5 | Yes | No |
| | SymlinkMax | No | 32 | Yes | No |
| | CoalesceElementChunkSize | No | 16 | Yes | No |
| | InodeRecCacheEvictLowLimit | Yes | | Yes | No |
| | InodeRecCacheEvictHighLimit | Yes | | Yes | No |
| | LogSegmentRecCacheEvictLowLimit | Yes | | Yes | No |
Expand Down
1 change: 1 addition & 0 deletions blunder/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func testSetup(t *testing.T) {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=32",
"FSGlobals.CoalesceElementChunkSize=16",
}

testConfMap, err = conf.MakeConfMapFromStrings(testConfStrings)
Expand Down
1 change: 1 addition & 0 deletions dlm/llm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ func testSetup() (err error) {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=32",
"FSGlobals.CoalesceElementChunkSize=16",
}

testConfMap, err = conf.MakeConfMapFromStrings(testConfMapStrings)
Expand Down
1 change: 1 addition & 0 deletions evtlog/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func TestAPI(t *testing.T) {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=32",
"FSGlobals.CoalesceElementChunkSize=16",
"EventLog.Enabled=true",
"EventLog.BufferKey=9876", // Don't conflict with a running instance
"EventLog.BufferLength=65536", // 64KiB
Expand Down
2 changes: 2 additions & 0 deletions evtlog/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func benchmarkSetup(b *testing.B, enable bool) {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=32",
"FSGlobals.CoalesceElementChunkSize=16",
"EventLog.Enabled=true",
"EventLog.BufferKey=1234",
"EventLog.BufferLength=65536", //64KiB
Expand All @@ -57,6 +58,7 @@ func benchmarkSetup(b *testing.B, enable bool) {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=32",
"FSGlobals.CoalesceElementChunkSize=16",
"EventLog.Enabled=false",
}
}
Expand Down
160 changes: 100 additions & 60 deletions fs/api_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -1381,19 +1381,20 @@ func (vS *volumeStruct) MiddlewareCoalesce(destPath string, metaData []byte, ele
ino uint64, numWrites uint64, attrChangeTime uint64, modificationTime uint64, err error) {

var (
coalesceElementList []*inode.CoalesceElement
coalesceElementListIndex int
coalesceSize uint64
ctime time.Time
mtime time.Time
destFileInodeNumber inode.InodeNumber
dirEntryBasename string
dirEntryInodeNumber inode.InodeNumber
dirInodeNumber inode.InodeNumber
elementPath string
heldLocks *heldLocksStruct
retryRequired bool
tryLockBackoffContext *tryLockBackoffContextStruct
coalesceElementList []*inode.CoalesceElement
coalesceSize uint64
ctime time.Time
destFileInodeNumber inode.InodeNumber
dirEntryBasename string
dirEntryInodeNumber inode.InodeNumber
dirInodeNumber inode.InodeNumber
elementPathIndex int
elementPathIndexAtChunkEnd int
elementPathIndexAtChunkStart int
heldLocks *heldLocksStruct
mtime time.Time
retryRequired bool
tryLockBackoffContext *tryLockBackoffContextStruct
)

startTime := time.Now()
Expand All @@ -1408,54 +1409,17 @@ func (vS *volumeStruct) MiddlewareCoalesce(destPath string, metaData []byte, ele
vS.jobRWMutex.RLock()
defer vS.jobRWMutex.RUnlock()

// Retry until done or failure (starting with ZERO backoff)
// First create the destination file if necessary and ensure that it is empty

tryLockBackoffContext = &tryLockBackoffContextStruct{}

Restart:

// Perform backoff and update for each restart (starting with ZERO backoff of course)
RestartDestinationFileCreation:

tryLockBackoffContext.backoff()

// Construct fresh heldLocks for this restart

heldLocks = newHeldLocks()

// Assemble WriteLock on each FileInode and their containing DirInode in elementPaths

coalesceElementList = make([]*inode.CoalesceElement, len(elementPaths))

for coalesceElementListIndex, elementPath = range elementPaths {
dirInodeNumber, dirEntryInodeNumber, dirEntryBasename, _, retryRequired, err =
vS.resolvePath(
inode.RootDirInodeNumber,
elementPath,
heldLocks,
resolvePathFollowDirSymlinks|
resolvePathRequireExclusiveLockOnDirEntryInode|
resolvePathRequireExclusiveLockOnDirInode)

if nil != err {
heldLocks.free()
return
}

if retryRequired {
heldLocks.free()
goto Restart
}

// Record dirInode & dirEntryInode (fileInode) in elementList

coalesceElementList[coalesceElementListIndex] = &inode.CoalesceElement{
ContainingDirectoryInodeNumber: dirInodeNumber,
ElementInodeNumber: dirEntryInodeNumber,
ElementName: dirEntryBasename,
}
}

_, dirEntryInodeNumber, _, _, retryRequired, err =
_, destFileInodeNumber, _, _, retryRequired, err =
vS.resolvePath(
inode.RootDirInodeNumber,
destPath,
Expand All @@ -1472,18 +1436,94 @@ Restart:

if retryRequired {
heldLocks.free()
goto Restart
goto RestartDestinationFileCreation
}

// Invoke package inode to actually perform the Coalesce operation
vS.inodeVolumeHandle.SetSize(destFileInodeNumber, 0)

destFileInodeNumber = dirEntryInodeNumber
ctime, mtime, numWrites, coalesceSize, err = vS.inodeVolumeHandle.Coalesce(
destFileInodeNumber, MiddlewareStream, metaData, coalesceElementList)
heldLocks.free()

// We can now release all the WriteLocks we are currently holding
// Now setup for looping through elementPaths with fresh locks
// every globals.coalesceElementChunkSize elements holding an
// Exclusive Lock on each FileInode and their containing DirInode

heldLocks.free()
elementPathIndexAtChunkStart = 0

for elementPathIndexAtChunkStart < len(elementPaths) {
elementPathIndexAtChunkEnd = elementPathIndexAtChunkStart + int(globals.coalesceElementChunkSize)
if elementPathIndexAtChunkEnd > len(elementPaths) {
elementPathIndexAtChunkEnd = len(elementPaths)
}

// Coalesce elementPaths[elementPathIndexAtChunkStart:elementPathIndexAtChunkEnd)

tryLockBackoffContext = &tryLockBackoffContextStruct{}

RestartCoalesceChunk:

tryLockBackoffContext.backoff()

heldLocks = newHeldLocks()

coalesceElementList = make([]*inode.CoalesceElement, 0, (elementPathIndexAtChunkEnd - elementPathIndexAtChunkStart))

for elementPathIndex = elementPathIndexAtChunkStart; elementPathIndex < elementPathIndexAtChunkEnd; elementPathIndex++ {
dirInodeNumber, dirEntryInodeNumber, dirEntryBasename, _, retryRequired, err =
vS.resolvePath(
inode.RootDirInodeNumber,
elementPaths[elementPathIndex],
heldLocks,
resolvePathFollowDirSymlinks|
resolvePathRequireExclusiveLockOnDirEntryInode|
resolvePathRequireExclusiveLockOnDirInode)

if nil != err {
heldLocks.free()
return
}

if retryRequired {
heldLocks.free()
goto RestartCoalesceChunk
}

coalesceElementList = append(coalesceElementList, &inode.CoalesceElement{
ContainingDirectoryInodeNumber: dirInodeNumber,
ElementInodeNumber: dirEntryInodeNumber,
ElementName: dirEntryBasename,
})
}

_, destFileInodeNumber, _, _, retryRequired, err =
vS.resolvePath(
inode.RootDirInodeNumber,
destPath,
heldLocks,
resolvePathFollowDirEntrySymlinks|
resolvePathFollowDirSymlinks|
resolvePathRequireExclusiveLockOnDirEntryInode)

if nil != err {
heldLocks.free()
return
}

if retryRequired {
heldLocks.free()
goto RestartCoalesceChunk
}

ctime, mtime, numWrites, coalesceSize, err = vS.inodeVolumeHandle.Coalesce(
destFileInodeNumber, MiddlewareStream, metaData, coalesceElementList)

heldLocks.free()

if nil != err {
return
}

elementPathIndexAtChunkStart = elementPathIndexAtChunkEnd
}

// Regardless of err return, fill in other return values

Expand Down
5 changes: 5 additions & 0 deletions fs/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type globalsStruct struct {
tryLockBackoffMax time.Duration
tryLockSerializationThreshhold uint64
symlinkMax uint16
coalesceElementChunkSize uint16

volumeMap map[string]*volumeStruct // key == volumeStruct.volumeName

Expand Down Expand Up @@ -204,6 +205,10 @@ func (dummy *globalsStruct) Up(confMap conf.ConfMap) (err error) {
if nil != err {
globals.symlinkMax = 32 // TODO: Eventually, just return
}
globals.coalesceElementChunkSize, err = confMap.FetchOptionValueUint16("FSGlobbals", "CoalesceElementChunkSize")
if nil != err {
globals.coalesceElementChunkSize = 16 // TODO: Eventually, just return
}

globals.volumeMap = make(map[string]*volumeStruct)

Expand Down
1 change: 1 addition & 0 deletions fs/setup_teardown_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ func testSetup(t *testing.T, starvationMode bool) {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=32",
"FSGlobals.CoalesceElementChunkSize=16",
"FSGlobals.InodeRecCacheEvictLowLimit=10000",
"FSGlobals.InodeRecCacheEvictHighLimit=10010",
"FSGlobals.LogSegmentRecCacheEvictLowLimit=10000",
Expand Down
1 change: 1 addition & 0 deletions halter/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func TestAPI(t *testing.T) {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=32",
"FSGlobals.CoalesceElementChunkSize=16",
}

testConfMap, err := conf.MakeConfMapFromStrings(testConfMapStrings)
Expand Down
1 change: 1 addition & 0 deletions headhunter/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ func TestHeadHunterAPI(t *testing.T) {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=32",
"FSGlobals.CoalesceElementChunkSize=16",
"FSGlobals.InodeRecCacheEvictLowLimit=10000",
"FSGlobals.InodeRecCacheEvictHighLimit=10010",
"FSGlobals.LogSegmentRecCacheEvictLowLimit=10000",
Expand Down
1 change: 1 addition & 0 deletions headhunter/stress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ func TestHeadHunterStress(t *testing.T) {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=32",
"FSGlobals.CoalesceElementChunkSize=16",
"FSGlobals.InodeRecCacheEvictLowLimit=10000",
"FSGlobals.InodeRecCacheEvictHighLimit=10010",
"FSGlobals.LogSegmentRecCacheEvictLowLimit=10000",
Expand Down
1 change: 1 addition & 0 deletions httpserver/setup_teardown_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func testSetup(t *testing.T) {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=32",
"FSGlobals.CoalesceElementChunkSize=16",
"FSGlobals.InodeRecCacheEvictLowLimit=10000",
"FSGlobals.InodeRecCacheEvictHighLimit=10010",
"FSGlobals.LogSegmentRecCacheEvictLowLimit=10000",
Expand Down
13 changes: 3 additions & 10 deletions inode/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -1138,24 +1138,17 @@ func (vS *volumeStruct) Coalesce(destInodeNumber InodeNumber, metaDataName strin
return
}

// Now truncate destInode & "append" each Element's extents to destInode (creating duplicate references to LogSegments for now)
// Now "append" each Element's extents to destInode (creating duplicate references to LogSegments for now)

destInodeExtentMap = destInode.payload.(sortedmap.BPlusTree)

destInode.dirty = true

err = setSizeInMemory(destInode, 0)
if nil != err {
err = blunder.NewError(blunder.InvalidArgError, "Coalesce() unable to truncate destInodeNumber 0x%016X: %v", destInodeNumber, err)
return
}

destInodeOffsetBeforeElementAppend = 0
destInode.NumWrites = 0
destInodeOffsetBeforeElementAppend = fileLen(destInodeExtentMap)

for _, element = range elements {
elementInode = inodeMap[element.ElementInodeNumber]
destInode.NumWrites += 1
destInode.NumWrites++
elementInodeExtentMap = elementInode.payload.(sortedmap.BPlusTree)
elementInodeExtentMapLen, err = elementInodeExtentMap.Len()
for elementInodeExtentMapIndex = 0; elementInodeExtentMapIndex < elementInodeExtentMapLen; elementInodeExtentMapIndex++ {
Expand Down
1 change: 1 addition & 0 deletions inode/setup_teardown_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ func testSetup(t *testing.T, starvationMode bool) {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=32",
"FSGlobals.CoalesceElementChunkSize=16",
"FSGlobals.InodeRecCacheEvictLowLimit=10000",
"FSGlobals.InodeRecCacheEvictHighLimit=10010",
"FSGlobals.LogSegmentRecCacheEvictLowLimit=10000",
Expand Down
1 change: 1 addition & 0 deletions jrpcfs/middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func testSetup() []func() {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=8",
"FSGlobals.CoalesceElementChunkSize=16",
"FSGlobals.InodeRecCacheEvictLowLimit=10000",
"FSGlobals.InodeRecCacheEvictHighLimit=10010",
"FSGlobals.LogSegmentRecCacheEvictLowLimit=10000",
Expand Down
1 change: 1 addition & 0 deletions pfsagentd/setup_teardown_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ func testSetup(t *testing.T) {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=32",
"FSGlobals.CoalesceElementChunkSize=16",
"FSGlobals.InodeRecCacheEvictLowLimit=10000",
"FSGlobals.InodeRecCacheEvictHighLimit=10010",
"FSGlobals.LogSegmentRecCacheEvictLowLimit=10000",
Expand Down
1 change: 1 addition & 0 deletions proxyfsd/daemon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ func TestDaemon(t *testing.T) {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=32",
"FSGlobals.CoalesceElementChunkSize=16",
"FSGlobals.InodeRecCacheEvictLowLimit=10000",
"FSGlobals.InodeRecCacheEvictHighLimit=10010",
"FSGlobals.LogSegmentRecCacheEvictLowLimit=10000",
Expand Down
1 change: 1 addition & 0 deletions proxyfsd/default.conf
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ TryLockBackoffMin: 10ms
TryLockBackoffMax: 50ms
TryLockSerializationThreshhold: 5
SymlinkMax: 32
CoalesceElementChunkSize: 16
InodeRecCacheEvictLowLimit: 10000
InodeRecCacheEvictHighLimit: 10010
LogSegmentRecCacheEvictLowLimit: 10000
Expand Down
1 change: 1 addition & 0 deletions proxyfsd/file_server.conf
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ TryLockBackoffMin: 10ms
TryLockBackoffMax: 50ms
TryLockSerializationThreshhold: 5
SymlinkMax: 32
CoalesceElementChunkSize: 16
InodeRecCacheEvictLowLimit: 10000
InodeRecCacheEvictHighLimit: 10010
LogSegmentRecCacheEvictLowLimit: 10000
Expand Down
1 change: 1 addition & 0 deletions proxyfsd/file_server_mac_3_peers.conf
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ TryLockBackoffMin: 10ms
TryLockBackoffMax: 50ms
TryLockSerializationThreshhold: 5
SymlinkMax: 32
CoalesceElementChunkSize: 16
InodeRecCacheEvictLowLimit: 10000
InodeRecCacheEvictHighLimit: 10010
LogSegmentRecCacheEvictLowLimit: 10000
Expand Down
1 change: 1 addition & 0 deletions ramswift/daemon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func TestViaNoAuthClient(t *testing.T) {
"FSGlobals.TryLockBackoffMax=50ms",
"FSGlobals.TryLockSerializationThreshhold=5",
"FSGlobals.SymlinkMax=32",
"FSGlobals.CoalesceElementChunkSize=16",
"Peer:Peer0.ReadCacheQuotaFraction=0.20",
"RamSwiftInfo.MaxAccountNameLength=256",
"RamSwiftInfo.MaxContainerNameLength=256",
Expand Down
Loading

0 comments on commit 1d9ad45

Please sign in to comment.