From cb686dcad0757083388102d2f3f87d40c0c2235a Mon Sep 17 00:00:00 2001 From: Seebs Date: Wed, 5 Feb 2020 15:02:11 -0600 Subject: [PATCH] make mmap test experiment with different amounts of mapping This is sort of prototype-ish, but the idea is that we use SetMaxMapCount from syswrap, which already exists, to let us test edge cases like "what happens if you only sometimes have mapped data". --- mmap_test.go | 37 +++++++++++++++++++++++++++++++------ server/server.go | 4 ++-- syswrap/mmap.go | 5 ++++- syswrap/os.go | 4 +++- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/mmap_test.go b/mmap_test.go index 1d2cbcfee..5ce157bc4 100644 --- a/mmap_test.go +++ b/mmap_test.go @@ -15,11 +15,13 @@ package pilosa import ( + "fmt" "math/rand" "runtime" "testing" "github.com/pilosa/pilosa/v2/logger" + "github.com/pilosa/pilosa/v2/syswrap" ) type cv struct { @@ -27,11 +29,7 @@ type cv struct { vals []int64 } -// This test should basically never fail, but it might if you were running -// out of available mmaps. Which you can fake up by adding '&& false' to the test -// in newGeneration in generation.go. So this is probably useless but it's -// a failure mode we've been bitten by once... -func TestMmapBehavior(t *testing.T) { +func forceSnapshotsCheckMapping(t *testing.T) { depth := uint(6) f := mustOpenBSIFragment("i", "f", viewStandard, 0) f.Logger = logger.NewLogfLogger(t) @@ -64,7 +62,11 @@ func TestMmapBehavior(t *testing.T) { // then invalidates the other map... for i := 0; i < 32; i++ { cv := values[i%len(values)] - runtime.GC() + // periodically force gc, so if we have a small pool of maps + // we'll go in and out of mapping mode + if i%5 == 0 { + runtime.GC() + } err := f.importValue(cv.cols, cv.vals, depth, (i%3 == 1)) if err != nil { t.Fatalf("importValue[%d]: %v", i, err) @@ -75,3 +77,26 @@ func TestMmapBehavior(t *testing.T) { } } } + +// This test should basically never fail, but it might if you were running +// out of available mmaps. Which you can fake up by adding '&& false' to the test +// in newGeneration in generation.go. So this is probably useless but it's +// a failure mode we've been bitten by once... +func TestMmapBehavior(t *testing.T) { + var changed bool + var original uint64 + defer func() { + syswrap.SetMaxMapCount(original) + }() + + for _, mmapMaxVal := range []uint64{0, 3} { + prev := syswrap.SetMaxMapCount(mmapMaxVal) + if !changed { + original = prev + changed = true + } + t.Run(fmt.Sprintf("maps%d", mmapMaxVal), func(t *testing.T) { + forceSnapshotsCheckMapping(t) + }) + } +} diff --git a/server/server.go b/server/server.go index e9edeb293..a8bf9e095 100644 --- a/server/server.go +++ b/server/server.go @@ -229,8 +229,8 @@ func (m *Command) SetupServer() error { runtime.SetBlockProfileRate(m.Config.Profile.BlockRate) runtime.SetMutexProfileFraction(m.Config.Profile.MutexFraction) - syswrap.SetMaxMapCount(m.Config.MaxMapCount) - syswrap.SetMaxFileCount(m.Config.MaxFileCount) + _ = syswrap.SetMaxMapCount(m.Config.MaxMapCount) + _ = syswrap.SetMaxFileCount(m.Config.MaxFileCount) err := m.setupLogger() if err != nil { diff --git a/syswrap/mmap.go b/syswrap/mmap.go index 95e819999..4b680780a 100644 --- a/syswrap/mmap.go +++ b/syswrap/mmap.go @@ -34,10 +34,13 @@ var ErrMaxMapCountReached = errors.New("maximum map count reached") var maxMapCount uint64 = 60000 var mu sync.RWMutex -func SetMaxMapCount(max uint64) { +// SetMaxMapCount sets the maximum map count, and returns the previous maximum. +func SetMaxMapCount(max uint64) uint64 { + prev := maxMapCount mu.Lock() maxMapCount = max mu.Unlock() + return prev } // Mmap increments the global map count, and then calls syscall.Mmap. It diff --git a/syswrap/os.go b/syswrap/os.go index 1704b0759..67f87fcd4 100644 --- a/syswrap/os.go +++ b/syswrap/os.go @@ -27,10 +27,12 @@ var fileCount uint64 var maxFileCount uint64 = 500000 var fileMu sync.RWMutex -func SetMaxFileCount(max uint64) { +func SetMaxFileCount(max uint64) uint64 { + prev := maxFileCount fileMu.Lock() maxFileCount = max fileMu.Unlock() + return prev } // OpenFile passes the arguments along to os.OpenFile while incrementing a