mirror of https://github.com/status-im/consul.git
Fixes a race condition when updating the state store during a snapshot restore.
This commit is contained in:
parent
b7b42d718a
commit
e4b88324b3
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/armon/go-metrics"
|
"github.com/armon/go-metrics"
|
||||||
|
@ -24,8 +25,15 @@ type consulFSM struct {
|
||||||
logOutput io.Writer
|
logOutput io.Writer
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
path string
|
path string
|
||||||
|
|
||||||
|
// stateLock is only used to protect outside callers to State() from
|
||||||
|
// racing with Restore(), which is called by Raft (it puts in a totally
|
||||||
|
// new state store). Everything else is synchronized by the Raft side,
|
||||||
|
// so doesn't need to lock this.
|
||||||
|
stateLock sync.RWMutex
|
||||||
state *state.StateStore
|
state *state.StateStore
|
||||||
gc *state.TombstoneGC
|
|
||||||
|
gc *state.TombstoneGC
|
||||||
}
|
}
|
||||||
|
|
||||||
// consulSnapshot is used to provide a snapshot of the current
|
// consulSnapshot is used to provide a snapshot of the current
|
||||||
|
@ -60,6 +68,8 @@ func NewFSM(gc *state.TombstoneGC, logOutput io.Writer) (*consulFSM, error) {
|
||||||
|
|
||||||
// State is used to return a handle to the current state
|
// State is used to return a handle to the current state
|
||||||
func (c *consulFSM) State() *state.StateStore {
|
func (c *consulFSM) State() *state.StateStore {
|
||||||
|
c.stateLock.RLock()
|
||||||
|
defer c.stateLock.RUnlock()
|
||||||
return c.state
|
return c.state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +326,12 @@ func (c *consulFSM) Restore(old io.ReadCloser) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// External code might be calling State(), so we need to synchronize
|
||||||
|
// here to make sure we swap in the new state store atomically.
|
||||||
|
c.stateLock.Lock()
|
||||||
c.state = stateNew
|
c.state = stateNew
|
||||||
|
c.stateLock.Unlock()
|
||||||
|
|
||||||
// Set up a new restore transaction
|
// Set up a new restore transaction
|
||||||
restore := c.state.Restore()
|
restore := c.state.Restore()
|
||||||
|
|
Loading…
Reference in New Issue