11package bench
22
33import (
4- bctx "context"
54 "fmt"
65 "math/rand"
7- "sync"
86 "time"
97
10- "github.com/FZambia/tarantool"
118 "github.com/tarantool/cartridge-cli/cli/context"
129)
1310
14- // printResults outputs benchmark foramatted results.
15- func printResults (results Results ) {
16- fmt .Printf ("\n Results:\n " )
17- fmt .Printf ("\t Success operations: %d\n " , results .successResultCount )
18- fmt .Printf ("\t Failed operations: %d\n " , results .failedResultCount )
19- fmt .Printf ("\t Request count: %d\n " , results .handledRequestsCount )
20- fmt .Printf ("\t Time (seconds): %f\n " , results .duration )
21- fmt .Printf ("\t Requests per second: %d\n \n " , results .requestsPerSecond )
22- }
23-
24- // verifyOperationsPercentage checks that the amount of operations percentage is 100.
25- func verifyOperationsPercentage (ctx * context.BenchCtx ) error {
26- entire_percentage := ctx .InsertCount + ctx .SelectCount + ctx .UpdateCount
27- if entire_percentage != 100 {
28- return fmt .Errorf (
29- "The number of operations as a percentage should be equal to 100, " +
30- "note that by default the percentage of inserts is 100" )
31- }
32- return nil
33- }
34-
35- // spacePreset prepares space for a benchmark.
36- func spacePreset (tarantoolConnection * tarantool.Connection ) error {
37- dropBenchmarkSpace (tarantoolConnection )
38- return createBenchmarkSpace (tarantoolConnection )
39- }
40-
41- // incrementRequest increases the counter of successful/failed requests depending on the presence of an error.
42- func (results * Results ) incrementRequestsCounters (err error ) {
43- if err == nil {
44- results .successResultCount ++
45- } else {
46- results .failedResultCount ++
47- }
48- results .handledRequestsCount ++
49- }
11+ // Main benchmark function.
12+ func Run (ctx context.BenchCtx ) error {
13+ rand .Seed (time .Now ().UnixNano ())
5014
51- // requestsLoop continuously executes the insert query until the benchmark time runs out.
52- func requestsLoop (requestsSequence * RequestsSequence , backgroundCtx bctx.Context ) {
53- for {
54- select {
55- case <- backgroundCtx .Done ():
56- return
57- default :
58- request := requestsSequence .getNext ()
59- request .operation (& request )
60- }
15+ if err := verifyOperationsPercentage (& ctx ); err != nil {
16+ return err
6117 }
62- }
6318
64- // connectionLoop runs "ctx.SimultaneousRequests" requests execution goroutines
65- // through the same connection.
66- func connectionLoop (
67- ctx * context.BenchCtx ,
68- requestsSequence * RequestsSequence ,
69- backgroundCtx bctx.Context ,
70- ) {
71- var connectionWait sync.WaitGroup
72- for i := 0 ; i < ctx .SimultaneousRequests ; i ++ {
73- connectionWait .Add (1 )
74- go func () {
75- defer connectionWait .Done ()
76- requestsLoop (requestsSequence , backgroundCtx )
77- }()
19+ // Check cluster topology for further actions.
20+ cluster , err := isCluster (ctx )
21+ if err != nil {
22+ return err
7823 }
7924
80- connectionWait .Wait ()
81- }
82-
83- // preFillBenchmarkSpaceIfRequired fills benchmark space
84- // if insert count = 0 or PreFillingCount flag is explicitly specified.
85- func preFillBenchmarkSpaceIfRequired (ctx context.BenchCtx , connectionPool []* tarantool.Connection ) error {
86- if ctx .InsertCount == 0 || ctx .PreFillingCount != PreFillingCount {
87- fmt .Println ("\n The pre-filling of the space has started,\n " +
88- "because the insert operation is not specified\n " +
89- "or there was an explicit instruction for pre-filling." )
90- fmt .Println ("..." )
91- filledCount , err := fillBenchmarkSpace (ctx , connectionPool )
92- if err != nil {
25+ if cluster {
26+ // Check cluster for wrong topology.
27+ if err := verifyClusterTopology (ctx ); err != nil {
9328 return err
9429 }
95- fmt .Printf ("Pre-filling is finished. Number of records: %d\n \n " , filledCount )
96- }
97- return nil
98- }
99-
100- // Main benchmark function.
101- func Run (ctx context.BenchCtx ) error {
102- rand .Seed (time .Now ().UnixNano ())
103-
104- if err := verifyOperationsPercentage (& ctx ); err != nil {
105- return err
30+ // Get url of one of instances in cluster for space preset and prefill.
31+ ctx .URL = (* ctx .Leaders )[0 ]
10632 }
10733
10834 // Connect to tarantool and preset space for benchmark.
109- tarantoolConnection , err := tarantool .Connect (ctx .URL , tarantool.Opts {
110- User : ctx .User ,
111- Password : ctx .Password ,
112- })
35+ tarantoolConnection , err := createConnection (ctx )
11336 if err != nil {
11437 return fmt .Errorf (
11538 "Couldn't connect to Tarantool %s." ,
@@ -123,87 +46,37 @@ func Run(ctx context.BenchCtx) error {
12346 return err
12447 }
12548
126- /// Сreate a "connectionPool" before starting the benchmark to exclude the connection establishment time from measurements.
127- connectionPool := make ([]* tarantool.Connection , ctx .Connections )
128- for i := 0 ; i < ctx .Connections ; i ++ {
129- connectionPool [i ], err = tarantool .Connect (ctx .URL , tarantool.Opts {
130- User : ctx .User ,
131- Password : ctx .Password ,
132- })
133- if err != nil {
134- return err
135- }
136- defer connectionPool [i ].Close ()
137- }
138-
139- if err := preFillBenchmarkSpaceIfRequired (ctx , connectionPool ); err != nil {
49+ if err := preFillBenchmarkSpaceIfRequired (ctx ); err != nil {
14050 return err
14151 }
14252
14353 fmt .Println ("Benchmark start" )
14454 fmt .Println ("..." )
14555
146- // The "context" will be used to stop all "connectionLoop" when the time is out.
147- backgroundCtx , cancel := bctx .WithCancel (bctx .Background ())
148- var waitGroup sync.WaitGroup
149- results := Results {}
150-
151- startTime := time .Now ()
152- timer := time .NewTimer (time .Duration (ctx .Duration * int (time .Second )))
153-
154- // Start detached connections.
155- for i := 0 ; i < ctx .Connections ; i ++ {
156- waitGroup .Add (1 )
157- go func (connection * tarantool.Connection ) {
158- defer waitGroup .Done ()
159- requestsSequence := RequestsSequence {
160- []RequestsGenerator {
161- {
162- Request {
163- insertOperation ,
164- ctx ,
165- connection ,
166- & results ,
167- },
168- ctx .InsertCount ,
169- },
170- {
171- Request {
172- selectOperation ,
173- ctx ,
174- connection ,
175- & results ,
176- },
177- ctx .SelectCount ,
178- },
179- {
180- Request {
181- updateOperation ,
182- ctx ,
183- connection ,
184- & results ,
185- },
186- ctx .UpdateCount ,
187- },
188- },
189- 0 ,
190- ctx .InsertCount ,
191- sync.Mutex {},
192- }
193- connectionLoop (& ctx , & requestsSequence , backgroundCtx )
194- }(connectionPool [i ])
56+ // Bench one instance by default.
57+ benchStart := benchOneInstance
58+ if cluster {
59+ benchStart = benchCluster
60+ }
61+
62+ // Prepare data for bench.
63+ benchData := getBenchData (ctx )
64+
65+ // Start benching.
66+ if err := benchStart (ctx , & benchData ); err != nil {
67+ return err
19568 }
196- // Sends "signal" to all "connectionLoop" and waits for them to complete.
197- <- timer .C
198- cancel ()
199- waitGroup .Wait ()
20069
201- results .duration = time .Since (startTime ).Seconds ()
202- results .requestsPerSecond = int (float64 (results .handledRequestsCount ) / results .duration )
70+ // Calculate results.
71+ benchData .results .duration = time .Since (benchData .startTime ).Seconds ()
72+ benchData .results .requestsPerSecond = int (float64 (benchData .results .handledRequestsCount ) / benchData .results .duration )
20373
204- dropBenchmarkSpace (tarantoolConnection )
205- fmt .Println ("Benchmark stop" )
74+ // Benchmark space must exist after bench.
75+ if err := dropBenchmarkSpace (tarantoolConnection ); err != nil {
76+ return err
77+ }
78+ fmt .Println ("Benchmark stop." )
20679
207- printResults (results )
80+ printResults (benchData . results )
20881 return nil
20982}
0 commit comments