Skip to content

Commit

Permalink
Limit filestore block size to 2MB when encryption is enabled
Browse files Browse the repository at this point in the history
Some write operations in the filestore require re-encrypting the
entire block, so having large blocks can make these operations
slow and hurt performance.

Signed-off-by: Neil Twigg <neil@nats.io>
  • Loading branch information
neilalexander committed Apr 13, 2023
1 parent 69b427b commit 856c09f
Showing 1 changed file with 17 additions and 4 deletions.
21 changes: 17 additions & 4 deletions server/filestore.go
Expand Up @@ -257,6 +257,8 @@ const (
// For smaller reuse buffers. Usually being generated during contention on the lead write buffer.
// E.g. mirrors/sources etc.
defaultSmallBlockSize = 1 * 1024 * 1024 // 1MB
// Maximum size for encrypted blocks.
maximumEncryptedBlockSize = 2 * 1024 * 1024 // 2MB
// Default for KV based
defaultKVBlockSize = defaultMediumBlockSize
// max block size for now.
Expand Down Expand Up @@ -288,7 +290,7 @@ func newFileStoreWithCreated(fcfg FileStoreConfig, cfg StreamConfig, created tim
}
// Default values.
if fcfg.BlockSize == 0 {
fcfg.BlockSize = dynBlkSize(cfg.Retention, cfg.MaxBytes)
fcfg.BlockSize = dynBlkSize(cfg.Retention, cfg.MaxBytes, fcfg.Cipher)
}
if fcfg.BlockSize > maxBlockSize {
return nil, fmt.Errorf("filestore max block size is %s", friendlyBytes(maxBlockSize))
Expand Down Expand Up @@ -451,7 +453,7 @@ func (fs *fileStore) UpdateConfig(cfg *StreamConfig) error {
return nil
}

func dynBlkSize(retention RetentionPolicy, maxBytes int64) uint64 {
func dynBlkSize(retention RetentionPolicy, maxBytes int64, cipher StoreCipher) uint64 {
if maxBytes > 0 {
blkSize := (maxBytes / 4) + 1 // (25% overhead)
// Round up to nearest 100
Expand All @@ -465,13 +467,24 @@ func dynBlkSize(retention RetentionPolicy, maxBytes int64) uint64 {
} else {
blkSize = defaultMediumBlockSize
}
if cipher != NoCipher && blkSize > maximumEncryptedBlockSize {
// Notes on this below.
blkSize = maximumEncryptedBlockSize
}
return uint64(blkSize)
}

if retention == LimitsPolicy {
switch {
case cipher != NoCipher:
// In the case of encrypted stores, large blocks can result in worsened perf
// since many writes on disk involve re-encrypting the entire block. For now,
// we will enforce a cap on the block size when encryption is enabled to avoid
// this.
return maximumEncryptedBlockSize
case retention == LimitsPolicy:
// TODO(dlc) - Make the blocksize relative to this if set.
return defaultLargeBlockSize
} else {
default:
// TODO(dlc) - Make the blocksize relative to this if set.
return defaultMediumBlockSize
}
Expand Down

0 comments on commit 856c09f

Please sign in to comment.