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

[dbnode] Ensure that bootstrap.Cache is always passed by reference #2703

Merged
merged 3 commits into from
Oct 7, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
67 changes: 67 additions & 0 deletions src/dbnode/storage/bootstrap/bootstrap_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 27 additions & 23 deletions src/dbnode/storage/bootstrap/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package bootstrap
import (
"errors"
"fmt"
"sync"

"github.com/m3db/m3/src/dbnode/namespace"
"github.com/m3db/m3/src/dbnode/persist"
Expand All @@ -35,22 +36,30 @@ var (
errInstrumentOptsNotSet = errors.New("instrumentOptions not set")
)

type cache struct {
sync.Once

fsOpts fs.Options
namespaceDetails []NamespaceDetails
infoFilesByNamespace InfoFilesByNamespace
iOpts instrument.Options
}

// NewCache creates a cache specifically to be used during the bootstrap process.
// Primarily a mechanism for passing info files along without needing to re-read them at each
// stage of the bootstrap process.
func NewCache(options CacheOptions) (Cache, error) {
if err := options.Validate(); err != nil {
return Cache{}, err
return nil, err
}
return Cache{
return &cache{
fsOpts: options.FilesystemOptions(),
namespaceDetails: options.NamespaceDetails(),
iOpts: options.InstrumentOptions(),
}, nil
}

// InfoFilesForNamespace returns the info files grouped by shard for the provided namespace.
func (c *Cache) InfoFilesForNamespace(ns namespace.Metadata) (InfoFileResultsPerShard, error) {
func (c *cache) InfoFilesForNamespace(ns namespace.Metadata) (InfoFileResultsPerShard, error) {
infoFilesByShard, ok := c.ReadInfoFiles()[ns]
// This should never happen as Cache object is initialized with all namespaces to bootstrap.
if !ok {
Expand All @@ -60,8 +69,7 @@ func (c *Cache) InfoFilesForNamespace(ns namespace.Metadata) (InfoFileResultsPer
return infoFilesByShard, nil
}

// InfoFilesForShard returns the info files grouped by shard for the provided namespace.
func (c *Cache) InfoFilesForShard(ns namespace.Metadata, shard uint32) ([]fs.ReadInfoFileResult, error) {
func (c *cache) InfoFilesForShard(ns namespace.Metadata, shard uint32) ([]fs.ReadInfoFileResult, error) {
infoFilesByShard, err := c.InfoFilesForNamespace(ns)
if err != nil {
return nil, err
Expand All @@ -75,24 +83,20 @@ func (c *Cache) InfoFilesForShard(ns namespace.Metadata, shard uint32) ([]fs.Rea
return infoFileResults, nil
}

// ReadInfoFiles returns info file results for each shard grouped by namespace. A cached copy
// is returned if the info files have already been read.
func (c *Cache) ReadInfoFiles() InfoFilesByNamespace {
if c.infoFilesByNamespace != nil {
return c.infoFilesByNamespace
}

c.infoFilesByNamespace = make(InfoFilesByNamespace, len(c.namespaceDetails))
for _, finder := range c.namespaceDetails {
result := make(InfoFileResultsPerShard, len(finder.Shards))
for _, shard := range finder.Shards {
result[shard] = fs.ReadInfoFiles(c.fsOpts.FilePathPrefix(),
finder.Namespace.ID(), shard, c.fsOpts.InfoReaderBufferSize(), c.fsOpts.DecodingOptions(),
persist.FileSetFlushType)
func (c *cache) ReadInfoFiles() InfoFilesByNamespace {
c.Once.Do(func() {
c.infoFilesByNamespace = make(InfoFilesByNamespace, len(c.namespaceDetails))
for _, finder := range c.namespaceDetails {
result := make(InfoFileResultsPerShard, len(finder.Shards))
for _, shard := range finder.Shards {
result[shard] = fs.ReadInfoFiles(c.fsOpts.FilePathPrefix(),
finder.Namespace.ID(), shard, c.fsOpts.InfoReaderBufferSize(), c.fsOpts.DecodingOptions(),
persist.FileSetFlushType)
}

c.infoFilesByNamespace[finder.Namespace] = result
}

c.infoFilesByNamespace[finder.Namespace] = result
}
})

return c.infoFilesByNamespace
}
Expand Down
17 changes: 10 additions & 7 deletions src/dbnode/storage/bootstrap/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,13 +430,16 @@ type InfoFileResultsPerShard map[uint32][]fs.ReadInfoFileResult
type InfoFilesByNamespace map[namespace.Metadata]InfoFileResultsPerShard

// Cache provides a snapshot of info files for use throughout all stages of the bootstrap.
// This struct is not threadsafe and relies on the single-threaded nature of the bootstrap
// process.
type Cache struct {
fsOpts fs.Options
namespaceDetails []NamespaceDetails
infoFilesByNamespace InfoFilesByNamespace
iOpts instrument.Options
type Cache interface {
// InfoFilesForNamespace returns the info files grouped by namespace.
InfoFilesForNamespace(ns namespace.Metadata) (InfoFileResultsPerShard, error)

// InfoFilesForShard returns the info files grouped by shard for the provided namespace.
InfoFilesForShard(ns namespace.Metadata, shard uint32) ([]fs.ReadInfoFileResult, error)

// ReadInfoFiles returns info file results for each shard grouped by namespace. A cached copy
// is returned if the info files have already been read.
ReadInfoFiles() InfoFilesByNamespace
}

// CacheOptions represents the options for Cache.
Expand Down