Skip to content

Commit 0c7743e

Browse files
committed
apply patch
1 parent d4f313e commit 0c7743e

File tree

4 files changed

+79
-93
lines changed

4 files changed

+79
-93
lines changed

shutdown_test.go

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -129,18 +129,16 @@ func testGracefulShutdown(t *testing.T, conn *Connection, inst *test_helpers.Tar
129129
func TestGracefulShutdown(t *testing.T) {
130130
test_helpers.SkipIfWatchersUnsupported(t)
131131

132-
var inst test_helpers.TarantoolInstance
133132
var conn *Connection
134-
var err error
135133

136-
inst, err = test_helpers.StartTarantool(shtdnSrvOpts)
134+
inst, err := test_helpers.StartTarantool(shtdnSrvOpts)
137135
require.Nil(t, err)
138136
defer test_helpers.StopTarantoolWithCleanup(inst)
139137

140138
conn = test_helpers.ConnectWithValidation(t, shtdnDialer, shtdnClntOpts)
141139
defer conn.Close()
142140

143-
testGracefulShutdown(t, conn, &inst)
141+
testGracefulShutdown(t, conn, inst)
144142
}
145143

146144
func TestCloseGraceful(t *testing.T) {
@@ -190,26 +188,23 @@ func TestCloseGraceful(t *testing.T) {
190188
func TestGracefulShutdownWithReconnect(t *testing.T) {
191189
test_helpers.SkipIfWatchersUnsupported(t)
192190

193-
var inst test_helpers.TarantoolInstance
194-
var err error
195-
196-
inst, err = test_helpers.StartTarantool(shtdnSrvOpts)
191+
inst, err := test_helpers.StartTarantool(shtdnSrvOpts)
197192
require.Nil(t, err)
198193
defer test_helpers.StopTarantoolWithCleanup(inst)
199194

200195
conn := test_helpers.ConnectWithValidation(t, shtdnDialer, shtdnClntOpts)
201196
defer conn.Close()
202197

203-
testGracefulShutdown(t, conn, &inst)
198+
testGracefulShutdown(t, conn, inst)
204199

205-
err = test_helpers.RestartTarantool(&inst)
200+
err = test_helpers.RestartTarantool(inst)
206201
require.Nilf(t, err, "Failed to restart tarantool")
207202

208203
connected := test_helpers.WaitUntilReconnected(conn, shtdnClntOpts.MaxReconnects,
209204
shtdnClntOpts.Reconnect)
210205
require.Truef(t, connected, "Reconnect success")
211206

212-
testGracefulShutdown(t, conn, &inst)
207+
testGracefulShutdown(t, conn, inst)
213208
}
214209

215210
func TestNoGracefulShutdown(t *testing.T) {
@@ -219,14 +214,12 @@ func TestNoGracefulShutdown(t *testing.T) {
219214
noShtdDialer.RequiredProtocolInfo = ProtocolInfo{}
220215
test_helpers.SkipIfWatchersSupported(t)
221216

222-
var inst test_helpers.TarantoolInstance
223217
var conn *Connection
224-
var err error
225218

226219
testSrvOpts := shtdnSrvOpts
227220
testSrvOpts.Dialer = noShtdDialer
228221

229-
inst, err = test_helpers.StartTarantool(testSrvOpts)
222+
inst, err := test_helpers.StartTarantool(testSrvOpts)
230223
require.Nil(t, err)
231224
defer test_helpers.StopTarantoolWithCleanup(inst)
232225

@@ -274,11 +267,9 @@ func TestNoGracefulShutdown(t *testing.T) {
274267
func TestGracefulShutdownRespectsClose(t *testing.T) {
275268
test_helpers.SkipIfWatchersUnsupported(t)
276269

277-
var inst test_helpers.TarantoolInstance
278270
var conn *Connection
279-
var err error
280271

281-
inst, err = test_helpers.StartTarantool(shtdnSrvOpts)
272+
inst, err := test_helpers.StartTarantool(shtdnSrvOpts)
282273
require.Nil(t, err)
283274
defer test_helpers.StopTarantoolWithCleanup(inst)
284275

@@ -354,11 +345,9 @@ func TestGracefulShutdownRespectsClose(t *testing.T) {
354345
func TestGracefulShutdownNotRacesWithRequestReconnect(t *testing.T) {
355346
test_helpers.SkipIfWatchersUnsupported(t)
356347

357-
var inst test_helpers.TarantoolInstance
358348
var conn *Connection
359-
var err error
360349

361-
inst, err = test_helpers.StartTarantool(shtdnSrvOpts)
350+
inst, err := test_helpers.StartTarantool(shtdnSrvOpts)
362351
require.Nil(t, err)
363352
defer test_helpers.StopTarantoolWithCleanup(inst)
364353

@@ -425,11 +414,9 @@ func TestGracefulShutdownNotRacesWithRequestReconnect(t *testing.T) {
425414
func TestGracefulShutdownCloseConcurrent(t *testing.T) {
426415
test_helpers.SkipIfWatchersUnsupported(t)
427416

428-
var inst test_helpers.TarantoolInstance
429-
var err error
430417
var srvShtdnStart, srvShtdnFinish time.Time
431418

432-
inst, err = test_helpers.StartTarantool(shtdnSrvOpts)
419+
inst, err := test_helpers.StartTarantool(shtdnSrvOpts)
433420
require.Nil(t, err)
434421
defer test_helpers.StopTarantoolWithCleanup(inst)
435422

@@ -492,7 +479,7 @@ func TestGracefulShutdownCloseConcurrent(t *testing.T) {
492479
sret = cerr
493480
}
494481
srvStop.Done()
495-
}(&inst)
482+
}(inst)
496483

497484
srvStop.Wait()
498485
require.Nil(t, sret, "No errors on server SIGTERM")
@@ -515,11 +502,9 @@ func TestGracefulShutdownCloseConcurrent(t *testing.T) {
515502
func TestGracefulShutdownConcurrent(t *testing.T) {
516503
test_helpers.SkipIfWatchersUnsupported(t)
517504

518-
var inst test_helpers.TarantoolInstance
519-
var err error
520505
var srvShtdnStart, srvShtdnFinish time.Time
521506

522-
inst, err = test_helpers.StartTarantool(shtdnSrvOpts)
507+
inst, err := test_helpers.StartTarantool(shtdnSrvOpts)
523508
require.Nil(t, err)
524509
defer test_helpers.StopTarantoolWithCleanup(inst)
525510

@@ -582,7 +567,7 @@ func TestGracefulShutdownConcurrent(t *testing.T) {
582567
sret = cerr
583568
}
584569
srvStop.Done()
585-
}(&inst)
570+
}(inst)
586571

587572
srvStop.Wait()
588573
require.Nil(t, sret, "No errors on server SIGTERM")

tarantool_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3609,7 +3609,7 @@ func TestConnection_NewWatcher_reconnect(t *testing.T) {
36093609
<-events
36103610

36113611
test_helpers.StopTarantool(inst)
3612-
if err := test_helpers.RestartTarantool(&inst); err != nil {
3612+
if err := test_helpers.RestartTarantool(inst); err != nil {
36133613
t.Fatalf("Unable to restart Tarantool: %s", err)
36143614
}
36153615

@@ -3902,7 +3902,7 @@ func TestConnection_named_index_after_reconnect(t *testing.T) {
39023902
t.Fatalf("An error expected.")
39033903
}
39043904

3905-
if err := test_helpers.RestartTarantool(&inst); err != nil {
3905+
if err := test_helpers.RestartTarantool(inst); err != nil {
39063906
t.Fatalf("Unable to restart Tarantool: %s", err)
39073907
}
39083908

test_helpers/main.go

Lines changed: 61 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ import (
2121
"path/filepath"
2222
"regexp"
2323
"strconv"
24-
"sync"
25-
"sync/atomic"
2624
"time"
2725

2826
"github.com/tarantool/go-tarantool/v2"
@@ -77,25 +75,10 @@ type StartOpts struct {
7775
Dialer tarantool.Dialer
7876
}
7977

80-
// errorWrap should be used with a pointer - as `optional` type.
81-
type errorWrap struct {
82-
err error
83-
}
84-
85-
type statusInstance struct {
86-
// status if nil, then process is not done yet.
87-
status *errorWrap
88-
// isStopping is a flag that terminate was internally initiated.
89-
isStopping atomic.Bool
90-
// waitMutex is used to prevent several invokes of the "Wait"
91-
// for the same process.
92-
// https://github.com/golang/go/issues/28461
93-
waitMutex sync.RWMutex
94-
}
95-
96-
// statusInstanceWrap used to avoid capturing content in defer function.
97-
type statusInstanceWrap struct {
98-
impl *statusInstance
78+
type state struct {
79+
done chan struct{}
80+
ret error
81+
stoped bool
9982
}
10083

10184
// TarantoolInstance is a data for instance graceful shutdown and cleanup.
@@ -109,64 +92,75 @@ type TarantoolInstance struct {
10992
// Dialer to check that connection established.
11093
Dialer tarantool.Dialer
11194

112-
st *statusInstanceWrap
113-
}
114-
115-
func newTarantoolInstance() TarantoolInstance {
116-
return TarantoolInstance{st: &statusInstanceWrap{&statusInstance{}}}
95+
st chan state
11796
}
11897

11998
func (t *TarantoolInstance) IsExit() bool {
120-
succeeded := t.st.impl.waitMutex.TryRLock()
121-
if !succeeded {
122-
// Due to mutex locked by goroutine, it means that process running.
99+
st := <-t.st
100+
t.st<- st
101+
102+
select {
103+
case <-st.done:
104+
default:
123105
return false
124106
}
125-
defer t.st.impl.waitMutex.RUnlock()
126-
return t.st.impl.status != nil
107+
108+
return st.ret != nil
127109
}
128110

129111
func (t *TarantoolInstance) result() error {
130-
succeeded := t.st.impl.waitMutex.TryRLock()
131-
if !succeeded {
112+
st := <-t.st
113+
t.st<- st
114+
115+
select {
116+
case <-st.done:
117+
default:
132118
return nil
133119
}
134-
defer t.st.impl.waitMutex.RUnlock()
135-
return t.st.impl.status.err
120+
121+
return st.ret
136122
}
137123

138124
func (t *TarantoolInstance) checkDone() {
139-
if t.st == nil || t.st.impl == nil {
140-
panic("TarantoolInstance is not initialized properly.")
141-
}
142-
143125
go func() {
144-
t.st.impl.waitMutex.Lock()
145-
defer t.st.impl.waitMutex.Unlock()
146-
t.st.impl.status = &errorWrap{t.Cmd.Wait()}
147-
if !t.st.impl.isStopping.Load() {
126+
ret := t.Cmd.Wait()
127+
128+
st := <-t.st
129+
130+
st.ret = ret
131+
close(st.done)
132+
133+
t.st<- st
134+
135+
if !st.stoped {
148136
log.Printf("Tarantool %q was unexpected terminated: %v", t.Opts.Listen, t.result())
149137
}
150138
}()
151139
}
152140

153141
func (t *TarantoolInstance) Wait() error {
154-
if t.st == nil {
155-
panic("TarantoolInstance is not initialized")
156-
}
157-
t.st.impl.waitMutex.RLock()
158-
defer t.st.impl.waitMutex.RUnlock()
159-
// Note: don't call `result()` here to avoid double locking.
160-
return t.st.impl.status.err
142+
st := <-t.st
143+
t.st<- st
144+
145+
<-st.done
146+
147+
st = <-t.st
148+
t.st<- st
149+
150+
return st.ret
161151
}
162152

163153
func (t *TarantoolInstance) Stop() error {
164154
if t == nil {
165155
log.Print("ASSERT: no Tarantool instance")
166156
return nil
167157
}
158+
159+
st := <-t.st
160+
st.stoped = true
161+
t.st<- st
162+
168163
log.Printf("Stopping Tarantool instance %q", t.Opts.Listen)
169-
t.st.impl.isStopping.Store(true)
170164
if t.IsExit() {
171165
log.Printf("Already stopped instance %q with result: %v", t.Opts.Listen, t.result())
172166
return nil
@@ -295,9 +289,10 @@ func IsTarantoolEE() (bool, error) {
295289
func RestartTarantool(inst *TarantoolInstance) error {
296290
log.Printf("Restarting Tarantool instance %q", inst.Opts.Listen)
297291
startedInst, err := StartTarantool(inst.Opts)
292+
298293
inst.Cmd.Process = startedInst.Cmd.Process
299-
// We can't change pointer to status instance, cause it could captured by `defer`.
300-
inst.st.impl = startedInst.st.impl
294+
inst.st = startedInst.st
295+
301296
return err
302297
}
303298

@@ -342,11 +337,17 @@ func prepareDir(workDir string) (string, error) {
342337
// StartTarantool starts a tarantool instance for tests
343338
// with specifies parameters (refer to StartOpts).
344339
// Process must be stopped with StopTarantool.
345-
func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
340+
func StartTarantool(startOpts StartOpts) (*TarantoolInstance, error) {
346341
// Prepare tarantool command.
347-
inst := newTarantoolInstance()
348-
var err error
342+
inst := &TarantoolInstance{
343+
st: make(chan state, 1),
344+
}
345+
init := state{
346+
done: make(chan struct{}),
347+
}
348+
inst.st <- init
349349

350+
var err error
350351
inst.Dialer = startOpts.Dialer
351352
startOpts.WorkDir, err = prepareDir(startOpts.WorkDir)
352353
if err != nil {
@@ -426,13 +427,13 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
426427

427428
if inst.IsExit() && inst.result() != nil {
428429
StopTarantool(inst)
429-
return TarantoolInstance{}, fmt.Errorf("unexpected terminated Tarantool %q: %w",
430+
return &TarantoolInstance{}, fmt.Errorf("unexpected terminated Tarantool %q: %w",
430431
inst.Opts.Listen, inst.result())
431432
}
432433

433434
if err != nil {
434435
StopTarantool(inst)
435-
return TarantoolInstance{}, fmt.Errorf("failed to connect Tarantool %q: %w",
436+
return &TarantoolInstance{}, fmt.Errorf("failed to connect Tarantool %q: %w",
436437
inst.Opts.Listen, err)
437438
}
438439

@@ -442,7 +443,7 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
442443
// StopTarantool stops a tarantool instance started
443444
// with StartTarantool. Waits until any resources
444445
// associated with the process is released. If something went wrong, fails.
445-
func StopTarantool(inst TarantoolInstance) {
446+
func StopTarantool(inst *TarantoolInstance) {
446447
err := inst.Stop()
447448
if err != nil {
448449
log.Fatal(err)
@@ -453,7 +454,7 @@ func StopTarantool(inst TarantoolInstance) {
453454
// with StartTarantool. Waits until any resources
454455
// associated with the process is released.
455456
// Cleans work directory after stop. If something went wrong, fails.
456-
func StopTarantoolWithCleanup(inst TarantoolInstance) {
457+
func StopTarantoolWithCleanup(inst *TarantoolInstance) {
457458
StopTarantool(inst)
458459

459460
if inst.Opts.WorkDir != "" {

test_helpers/pool_helper.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,8 @@ func SetClusterRO(dialers []tarantool.Dialer, connOpts tarantool.Opts,
227227
return nil
228228
}
229229

230-
func StartTarantoolInstances(instsOpts []StartOpts) ([]TarantoolInstance, error) {
231-
instances := make([]TarantoolInstance, 0, len(instsOpts))
230+
func StartTarantoolInstances(instsOpts []StartOpts) ([]*TarantoolInstance, error) {
231+
instances := make([]*TarantoolInstance, 0, len(instsOpts))
232232

233233
for _, opts := range instsOpts {
234234
instance, err := StartTarantool(opts)
@@ -243,7 +243,7 @@ func StartTarantoolInstances(instsOpts []StartOpts) ([]TarantoolInstance, error)
243243
return instances, nil
244244
}
245245

246-
func StopTarantoolInstances(instances []TarantoolInstance) {
246+
func StopTarantoolInstances(instances []*TarantoolInstance) {
247247
for _, instance := range instances {
248248
StopTarantoolWithCleanup(instance)
249249
}

0 commit comments

Comments
 (0)