Conversation
This adds a `candidate` flag to the config which tells the node whether it can become the primary or not. It defaults to true. Co-authored-by: Justin Whear <justin.whear@gmail.com> Co-authored-by: Ben Johnson <benbjohnson@yahoo.com>
|
@jwhear Thanks for the implementation. You're marked as the I mostly made small tweaks from your commit and added a functional test. |
benbjohnson
left a comment
There was a problem hiding this comment.
@jwhear I marked the changes in the commit in comments in this review.
| MountDir string `yaml:"mount-dir"` | ||
| Exec string `yaml:"exec"` | ||
| Debug bool `yaml:"debug"` | ||
| Candidate bool `yaml:"candidate"` |
There was a problem hiding this comment.
I renamed this from IsPrimaryCandidate to simply Candidate.
| func TestMultiNode_Candidate(t *testing.T) { | ||
| m0 := runMain(t, newMain(t, t.TempDir(), nil)) | ||
| waitForPrimary(t, m0) | ||
| m1 := newMain(t, t.TempDir(), m0) | ||
| m1.Config.Candidate = false | ||
| runMain(t, m1) | ||
| db0 := testingutil.OpenSQLDB(t, filepath.Join(m0.Config.MountDir, "db")) | ||
|
|
||
| // Create a database and wait for sync. | ||
| if _, err := db0.Exec(`CREATE TABLE t (x)`); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| waitForSync(t, 1, m0, m1) | ||
|
|
||
| // Stop the primary. | ||
| t.Log("shutting down primary node") | ||
| if err := db0.Close(); err != nil { | ||
| t.Fatal(err) | ||
| } else if err := m0.Close(); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
|
|
||
| // Second node is NOT a candidate so it should not become primary. | ||
| t.Log("waiting to ensure replica is not promoted...") | ||
| time.Sleep(3 * time.Second) | ||
| if m1.Store.IsPrimary() { | ||
| t.Fatalf("replica should not have been promoted to primary") | ||
| } | ||
|
|
||
| // Reopen first node and ensure it can become primary again. | ||
| t.Log("restarting first node as replica") | ||
| m0 = runMain(t, newMain(t, m0.Config.MountDir, m1)) | ||
| waitForPrimary(t, m0) | ||
| } | ||
|
|
There was a problem hiding this comment.
Added a test to make sure it works.
| // Candidate returns true if store is eligible to be the primary. | ||
| func (s *Store) Candidate() bool { | ||
| return s.candidate | ||
| } | ||
|
|
There was a problem hiding this comment.
This previously had a lock around it but the field is only written once on initialization so it doesn't need one.
| if err == ErrNoPrimary && !s.candidate { | ||
| log.Printf("cannot find primary & ineligible to become primary, retrying: %s", err) | ||
| time.Sleep(1 * time.Second) | ||
| continue |
There was a problem hiding this comment.
I propagated the logging up a level so it wouldn't do duplicate logging.
This pull request adds a
candidateflag to the config which tells the node whether it can become the primary or not. It defaults totrue.Original PR: jwhear#1
Fixes #16