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

Avoid stat syscall when planning compactions #7335

Merged
merged 1 commit into from
Sep 26, 2016
Merged

Conversation

jwilder
Copy link
Contributor

@jwilder jwilder commented Sep 20, 2016

Required for all non-trivial PRs
  • Rebased/mergable
  • Tests pass

When the planner runs, it needs to determine if any files have tombstones.
The code to determine if a tombstone existed involved stating the .tombstone
file. Since the planner runs very frequently and when there are many shards, this
causes a lot of system calls that are unnecessary.

Instead, cache the results of the stats calls and only refresh them when we
haven't checked at least once or we write new tombstone data.

This also caches the results of the TSMReader.Stats call to avoid creating
garbage.

@mention-bot
Copy link

@jwilder, thanks for your PR! By analyzing the annotation information on this pull request, we identified @joelegasse to be a potential reviewer

@jwilder jwilder force-pushed the jw-tsm-syscalls branch 4 times, most recently from 5facad9 to 9a03791 Compare September 23, 2016 15:05
Copy link
Contributor

@joelegasse joelegasse left a comment

Choose a reason for hiding this comment

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

The idea works, but there's a logic concern in HasTombstones and a data integrity concern with caching and returning the same slice, rather than just returning a copy of the data.

stat, err := os.Stat(t.tombstonePath())
if err != nil {
if os.IsNotExist(err) {
Copy link
Contributor

Choose a reason for hiding this comment

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

this could be if os.IsNotExist(err) || err != nil { with t.statsLoaded = err == nil

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this needs to be t.stasLoaded = os.IsNotExist(err) since error will never be nil.

Copy link
Contributor

Choose a reason for hiding this comment

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

That makes a lot more sense...


// Path is the location of the file to record tombstone. This should be the
// full path to a TSM file.
Path string

// cache of the stats for this tombstone
fileStats []FileStat
Copy link
Contributor

Choose a reason for hiding this comment

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

I think just caching the FileStat object as a value might be better

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm caching the slice because the interface returned is []FileStat Otherwise it allocates a slice each time.

Copy link
Contributor

Choose a reason for hiding this comment

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

There's still the concern of the data being modified, though. If we're okay with expecting the result to be used in a read-only fashion, then there are some other changes to allocate the slice exactly once: use t.fileStats = t.fileStats[:0] rather than assigning nil, and t.fileStats = append(t.fileStats[:0], FileStat{ ... instead of assigning a new slice.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not worried about it being modified, it's read-only. Re-using the slice is a better idea than setting it to nil too.


return stat.Size() > 0
t.mu.RLock()
b := len(t.fileStats) > 0 && t.fileStats[0].Size > 0
Copy link
Contributor

Choose a reason for hiding this comment

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

This should probably validate that os.Stat was at least called once, possibly checking t.statsLoaded first, then falling back to calling TombstoneFiles (or ensuring the cache gets populated)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point.

@jwilder
Copy link
Contributor Author

jwilder commented Sep 23, 2016

@joelegasse Updated.

Copy link
Contributor

@joelegasse joelegasse left a comment

Choose a reason for hiding this comment

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

Looks good, just missed one thing

LastModified: stat.ModTime().UnixNano(),
Size: uint32(stat.Size())}}
t.mu.Lock()
stats := []FileStat{FileStat{
Copy link
Contributor

Choose a reason for hiding this comment

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

in order to re-use the backing array, this should be t.fileStats = append(t.fileStats[:0], FileStat{

When the planner runs, it needs to determine if any files have tombstones.
The code to determine if a tombstone existed involved stating the .tombstone
file.  Since the planner runs very frequently when there are many shards, this
causea a lot of system calls that are unnecessary.

Instead, cache the results of the stats calls and only refresh them when we
haven't checked at least once or we write new tombstone data.

This also caches the results of the TSMReader.Stats call to avoid creating
garbage.
@jwilder
Copy link
Contributor Author

jwilder commented Sep 26, 2016

@joelegasse Should be good now.

Copy link
Contributor

@joelegasse joelegasse left a comment

Choose a reason for hiding this comment

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

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants