Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion go/vt/vttablet/tabletserver/state_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,14 @@ type servingState int64

const (
// StateNotConnected is the state where tabletserver is not
// connected to an underlying mysql instance.
// connected to an underlying mysql instance. In this state we close
// query engine since MySQL is probably unavailable
StateNotConnected = servingState(iota)
// StateNotServing is the state where tabletserver is connected
// to an underlying mysql instance, but is not serving queries.
// We do not close the query engine to not close the pool. We keep
// the query engine open but prevent queries from running by blocking them
// in StartRequest.
StateNotServing
// StateServing is where queries are allowed.
StateServing
Expand Down Expand Up @@ -325,11 +329,25 @@ func (sm *stateManager) CheckMySQL() {
}
defer sm.transitioning.Release()

// This is required to prevent new queries from running in StartRequest
// unless they are part of a running transaction.
sm.setWantState(StateNotConnected)
sm.closeAll()

// Now that we reached the NotConnected state, we want to go back to the
// Serving state. The retry will only succeed once MySQL is reachable again
// Until then EnsureConnectionAndDB will error out.
sm.setWantState(StateServing)
sm.retryTransition(fmt.Sprintf("Cannot connect to MySQL, shutting down query service: %v", err))
}()
}

func (sm *stateManager) setWantState(stateWanted servingState) {
sm.mu.Lock()
defer sm.mu.Unlock()
sm.wantState = stateWanted
}

// StopService shuts down sm. If the shutdown doesn't complete
// within timeBombDuration, it crashes the process.
func (sm *stateManager) StopService() {
Expand Down
8 changes: 8 additions & 0 deletions go/vt/vttablet/tabletserver/state_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -457,9 +457,16 @@ func TestStateManagerCheckMySQL(t *testing.T) {
err := sm.SetServingType(topodatapb.TabletType_PRIMARY, testNow, StateServing, "")
require.NoError(t, err)

sm.te = &delayedTxEngine{}
sm.qe.(*testQueryEngine).failMySQL = true
order.Set(0)
sm.CheckMySQL()
// We know checkMySQL will take atleast 50 milliseconds since txEngine.Close has a sleep in the test code
time.Sleep(10 * time.Millisecond)
// this asserts that checkMySQL is running
assert.EqualValues(t, 0, sm.checkMySQLThrottler.Size())
// When we are in CheckMySQL state, we should not be accepting any new requests which aren't transactional
assert.False(t, sm.IsServing())

// Rechecking immediately should be a no-op:
sm.CheckMySQL()
Expand Down Expand Up @@ -491,6 +498,7 @@ func TestStateManagerCheckMySQL(t *testing.T) {
time.Sleep(10 * time.Millisecond)
}

assert.True(t, sm.IsServing())
assert.Equal(t, topodatapb.TabletType_PRIMARY, sm.Target().TabletType)
assert.Equal(t, StateServing, sm.State())
}
Expand Down