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

tx: load freelist on Check() #49

Closed

Conversation

heyitsanthony
Copy link
Contributor

Fixes #45

@codecov-io
Copy link

Codecov Report

❗ No coverage uploaded for pull request base (master@2760028). Click here to learn what that means.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master      #49   +/-   ##
=========================================
  Coverage          ?   85.59%           
=========================================
  Files             ?        9           
  Lines             ?     1860           
  Branches          ?        0           
=========================================
  Hits              ?     1592           
  Misses            ?      159           
  Partials          ?      109
Impacted Files Coverage Δ
db.go 82.94% <100%> (ø)
tx.go 76.21% <100%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2760028...6f3dcc3. Read the comment docs.

@heyitsanthony
Copy link
Contributor Author

added a little extra synchronization machinery to handle this, but it shouldn't impact the common path

@@ -282,6 +278,26 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
return db, nil
}

// readFreelist is called on Open and tx.Check. It assumes there are no
// concurrenct accesses are being made to the freelist.
Copy link
Contributor

Choose a reason for hiding this comment

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

"concurrent accesses being made to the freelist."

db.stats.FreePageN = len(db.freelist.ids)
close(db.freelistReady)
})
<-db.freelistReady
Copy link
Contributor

Choose a reason for hiding this comment

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

Conveniently, it looks like we don't need the freelistReady channel. Since "...no call to Do returns until the one call to f returns" (go sync.Once docs), we don't need to wait on the freelistReady channel, it is guaranteed to always be closed.

Go playground sanity check: https://play.golang.org/p/ZJEX1V-IbY

@@ -282,6 +278,26 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
return db, nil
}

// readFreelist is called on Open and tx.Check. It assumes there are no
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we rename this to loadFreelist? That might more strongly suggest what side effects it has.

Might also be worth summarizing purpose of the function in a bit more detail, e.g:

"loadFreelist reads the freelist if it is synced, or reconstructs it by scanning the DB if it is not synced. This must be called before any operations that require on the freelist are executed...."

@@ -282,6 +278,26 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
return db, nil
}

// readFreelist is called on Open and tx.Check. It assumes there are no
// concurrenct accesses are being made to the freelist.
func (db *DB) readFreelist() bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

I found the return value of this function a bit tricky to reason about.

It might be cleaner to not return bool and fully separate the concerns of loading the freelist in readFreelist from the concerns of flushing the freelist in db.Open. E.g.:

db.Open:

...
if db.readOnly {
	return db, nil
}
hasFreeList := db.meta().freelist != pgidNoFreelist
db.readFreelist()

if !db.NoFreelistSync && !hasFreeList {
...

db.readFreelist:

func (db *DB) readFreelist() {
  b.freelistLoad.Do(func() {
		hasFreeList := db.meta().freelist != pgidNoFreelist
		db.freelist = newFreelist()
		if !hasFreeList {
...

And we could even add a db.hasSyncedFreelist() function to encapsulate the db.meta().freelist != pgidNoFreelist check and clean up the code a bit more.

@jpbetz
Copy link
Contributor

jpbetz commented Sep 21, 2017

We will be completing this PR via #52.

@xiang90
Copy link
Contributor

xiang90 commented Sep 22, 2017

closing in favor of #49

@xiang90 xiang90 closed this Sep 22, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants