1
0
Fork 0

Handle non-open Stores

master
Philip O'Toole 7 months ago
parent 0a9b71b7a9
commit 70cfe680cc

@ -1,6 +1,7 @@
## 8.21.2 (February 23rd 2024) ## 8.21.3 (unreleased)
### Implementation changes and bug fixes ### Implementation changes and bug fixes
- [PR #1697](https://github.com/rqlite/rqlite/pull/1697): Use consistent file perms post Boot. - [PR #1700](https://github.com/rqlite/rqlite/pull/1700): Accessing non-open Store shouldn't panic. Fixes issue [#1698](https://github.com/rqlite/rqlite/issues/1698).
## 8.21.1 (February 21st 2024) ## 8.21.1 (February 21st 2024)
### Implementation changes and bug fixes ### Implementation changes and bug fixes

@ -591,6 +591,9 @@ func (s *Store) Bootstrap(servers ...*Server) error {
// the cluster. If this node is not the leader, and 'wait' is true, an error // the cluster. If this node is not the leader, and 'wait' is true, an error
// will be returned. // will be returned.
func (s *Store) Stepdown(wait bool) error { func (s *Store) Stepdown(wait bool) error {
if !s.open {
return ErrNotOpen
}
f := s.raft.LeadershipTransfer() f := s.raft.LeadershipTransfer()
if !wait { if !wait {
return nil return nil
@ -760,11 +763,17 @@ func (s *Store) DBAppliedIndex() uint64 {
// IsLeader is used to determine if the current node is cluster leader // IsLeader is used to determine if the current node is cluster leader
func (s *Store) IsLeader() bool { func (s *Store) IsLeader() bool {
if !s.open {
return false
}
return s.raft.State() == raft.Leader return s.raft.State() == raft.Leader
} }
// HasLeader returns true if the cluster has a leader, false otherwise. // HasLeader returns true if the cluster has a leader, false otherwise.
func (s *Store) HasLeader() bool { func (s *Store) HasLeader() bool {
if !s.open {
return false
}
return s.raft.Leader() != "" return s.raft.Leader() != ""
} }
@ -772,6 +781,9 @@ func (s *Store) HasLeader() bool {
// is no reference to the current node in the current cluster configuration then // is no reference to the current node in the current cluster configuration then
// false will also be returned. // false will also be returned.
func (s *Store) IsVoter() (bool, error) { func (s *Store) IsVoter() (bool, error) {
if !s.open {
return false, ErrNotOpen
}
cfg := s.raft.GetConfiguration() cfg := s.raft.GetConfiguration()
if err := cfg.Error(); err != nil { if err := cfg.Error(); err != nil {
return false, err return false, err
@ -786,6 +798,9 @@ func (s *Store) IsVoter() (bool, error) {
// State returns the current node's Raft state // State returns the current node's Raft state
func (s *Store) State() ClusterState { func (s *Store) State() ClusterState {
if !s.open {
return Unknown
}
state := s.raft.State() state := s.raft.State()
switch state { switch state {
case raft.Leader: case raft.Leader:
@ -856,6 +871,9 @@ func (s *Store) LeaderWithID() (string, string) {
// CommitIndex returns the Raft commit index. // CommitIndex returns the Raft commit index.
func (s *Store) CommitIndex() (uint64, error) { func (s *Store) CommitIndex() (uint64, error) {
if !s.open {
return 0, ErrNotOpen
}
return s.raft.CommitIndex(), nil return s.raft.CommitIndex(), nil
} }
@ -863,6 +881,9 @@ func (s *Store) CommitIndex() (uint64, error) {
// by the latest AppendEntries RPC. If this node is the Leader then the // by the latest AppendEntries RPC. If this node is the Leader then the
// commit index is returned directly from the Raft object. // commit index is returned directly from the Raft object.
func (s *Store) LeaderCommitIndex() (uint64, error) { func (s *Store) LeaderCommitIndex() (uint64, error) {
if !s.open {
return 0, ErrNotOpen
}
if s.raft.State() == raft.Leader { if s.raft.State() == raft.Leader {
return s.raft.CommitIndex(), nil return s.raft.CommitIndex(), nil
} }

@ -22,6 +22,47 @@ import (
"github.com/rqlite/rqlite/v8/testdata/chinook" "github.com/rqlite/rqlite/v8/testdata/chinook"
) )
// Test_StoreSingleNode tests that a non-open Store handles public methods correctly.
func Test_NonOpenStore(t *testing.T) {
s, ln := mustNewStore(t)
defer s.Close(true)
defer ln.Close()
if err := s.Stepdown(false); err != ErrNotOpen {
t.Fatalf("wrong error received for non-open store: %s", err)
}
if s.IsLeader() {
t.Fatalf("store incorrectly marked as leader")
}
if s.HasLeader() {
t.Fatalf("store incorrectly marked as having leader")
}
if _, err := s.IsVoter(); err != ErrNotOpen {
t.Fatalf("wrong error received for non-open store: %s", err)
}
if s.State() != Unknown {
t.Fatalf("wrong cluster state returned for non-open store")
}
if _, err := s.CommitIndex(); err != ErrNotOpen {
t.Fatalf("wrong error received for non-open store: %s", err)
}
if _, err := s.LeaderCommitIndex(); err != ErrNotOpen {
t.Fatalf("wrong error received for non-open store: %s", err)
}
if addr, err := s.LeaderAddr(); addr != "" || err != nil {
t.Fatalf("wrong leader address returned for non-open store: %s", addr)
}
if id, err := s.LeaderID(); id != "" || err != nil {
t.Fatalf("wrong leader ID returned for non-open store: %s", id)
}
if addr, id := s.LeaderWithID(); addr != "" || id != "" {
t.Fatalf("wrong leader address and ID returned for non-open store: %s", id)
}
if _, err := s.Nodes(); err != ErrNotOpen {
t.Fatalf("wrong error received for non-open store: %s", err)
}
}
// Test_StoreSingleNode tests that a single node basically operates. // Test_StoreSingleNode tests that a single node basically operates.
func Test_OpenStoreSingleNode(t *testing.T) { func Test_OpenStoreSingleNode(t *testing.T) {
s, ln := mustNewStore(t) s, ln := mustNewStore(t)

Loading…
Cancel
Save