Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log when MAP_POPULATE gets disabled #28526

Merged
merged 14 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/28526.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
physical/raft: Log when the MAP_POPULATE mmap flag gets disabled before opening the database.
```
27 changes: 27 additions & 0 deletions physical/raft/bolt_64bit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,30 @@
})
}
}

func TestMmapFlags(t *testing.T) {

Check failure on line 47 in physical/raft/bolt_64bit_test.go

View workflow job for this annotation

GitHub Actions / Code checks

Test TestMmapFlags is missing a go doc
t.Parallel()
digivava marked this conversation as resolved.
Show resolved Hide resolved

testCases := []struct {
name string
disableMapPopulate bool
}{
{"MAP_POPULATE is enabled", false},
{"MAP_POPULATE disabled by env var", true},
}

for _, tc := range testCases {
tc := tc

t.Run(tc.name, func(t *testing.T) {
if tc.disableMapPopulate {
os.Setenv("VAULT_RAFT_DISABLE_MAP_POPULATE", "true")
digivava marked this conversation as resolved.
Show resolved Hide resolved
}

isEnabled := usingMapPopulate(getMmapFlags(""))
if tc.disableMapPopulate && isEnabled {
t.Error("expected MAP_POPULATE to be disabled but it was enabled")
}
})
}
}
32 changes: 27 additions & 5 deletions physical/raft/bolt_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,49 @@ import (

func init() {
getMmapFlags = getMmapFlagsLinux
usingMapPopulate = usingMapPopulateLinux
}

func getMmapFlagsLinux(dbPath string) int {
if setMapPopulateFlag(dbPath) {
return unix.MAP_POPULATE
}

return 0
}

// setMapPopulateFlag determines whether we should set the MAP_POPULATE flag, which
// prepopulates page tables to be mapped in the virtual memory space,
// helping reduce slowness at runtime caused by page faults.
// We only want to set this flag if we've determined there's enough memory on the system available to do so.
func setMapPopulateFlag(dbPath string) bool {
if os.Getenv("VAULT_RAFT_DISABLE_MAP_POPULATE") != "" {
return 0
return false
}
stat, err := os.Stat(dbPath)
if err != nil {
return 0
return false
}
size := stat.Size()

v, err := mem.VirtualMemoryWithContext(context.Background())
if err != nil {
return 0
return false
}

// We won't worry about swap, since we already tell people not to use it.
if v.Total > uint64(size) {
return unix.MAP_POPULATE
return true
}

return 0
return false
}

// the unix.MAP_POPULATE constant only exists on Linux,
// so reference to this constant can only live in a *_linux.go file
func usingMapPopulateLinux(mmapFlag int) bool {
if mmapFlag == unix.MAP_POPULATE {
return true
}
return false
}
8 changes: 8 additions & 0 deletions physical/raft/fsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"io"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -246,9 +247,11 @@ func (f *FSM) openDBFile(dbPath string) error {
return errors.New("can not open empty filename")
}

vaultDbExists := true
st, err := os.Stat(dbPath)
switch {
case err != nil && os.IsNotExist(err):
vaultDbExists = false
case err != nil:
return fmt.Errorf("error checking raft FSM db file %q: %v", dbPath, err)
default:
Expand All @@ -260,11 +263,16 @@ func (f *FSM) openDBFile(dbPath string) error {
}

opts := boltOptions(dbPath)
if runtime.GOOS == "linux" && vaultDbExists && !usingMapPopulate(opts.MmapFlags) {
f.logger.Warn("the MAP_POPULATE mmap flag has not been set before opening the FSM database. This may be due to the database file being larger than the available memory on the system, or due to the VAULT_RAFT_DISABLE_MAP_POPULATE environment variable being set. As a result, Vault may be slower to start up.")
}

start := time.Now()
boltDB, err := bolt.Open(dbPath, 0o600, opts)
if err != nil {
return err
}

elapsed := time.Now().Sub(start)
f.logger.Debug("time to open database", "elapsed", elapsed, "path", dbPath)
metrics.MeasureSince([]string{"raft_storage", "fsm", "open_db_file"}, start)
Expand Down
12 changes: 11 additions & 1 deletion physical/raft/raft.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"net/url"
"os"
"path/filepath"
"runtime"
"strconv"
"sync"
"sync/atomic"
Expand Down Expand Up @@ -74,7 +75,10 @@ const (
defaultMaxBatchSize = 128 * 1024
)

var getMmapFlags = func(string) int { return 0 }
var (
getMmapFlags = func(string) int { return 0 }
usingMapPopulate = func(int) bool { return false }
)

// Verify RaftBackend satisfies the correct interfaces
var (
Expand Down Expand Up @@ -447,6 +451,7 @@ func NewRaftBackend(conf map[string]string, logger log.Logger) (physical.Backend
}
}

// Create the log store.
Copy link
Collaborator Author

@digivava digivava Sep 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this to match the comment up above where we explain that we're creating the FSM. Helps people like me who are new to the concept that Vault has two different databases that need to be created.

// Build an all in-memory setup for dev mode, otherwise prepare a full
// disk-based setup.
var logStore raft.LogStore
Expand All @@ -473,6 +478,7 @@ func NewRaftBackend(conf map[string]string, logger log.Logger) (physical.Backend
if err != nil {
return nil, fmt.Errorf("failed to check if raft.db already exists: %w", err)
}

if backendConfig.RaftWal && raftDbExists {
logger.Warn("raft is configured to use raft-wal for storage but existing raft.db detected. raft-wal config will be ignored.")
backendConfig.RaftWal = false
Expand Down Expand Up @@ -504,6 +510,10 @@ func NewRaftBackend(conf map[string]string, logger log.Logger) (physical.Backend
MsgpackUseNewTimeFormat: true,
}

if runtime.GOOS == "linux" && raftDbExists && !usingMapPopulate(opts.MmapFlags) {
logger.Warn("the MAP_POPULATE mmap flag has not been set before opening the log store database. This may be due to the database file being larger than the available memory on the system, or due to the VAULT_RAFT_DISABLE_MAP_POPULATE environment variable being set. As a result, Vault may be slower to start up.")
}

store, err := raftboltdb.New(raftOptions)
if err != nil {
return nil, err
Expand Down
Loading